2017-01-24 2 views
1

Я делаю тест с клиентским приложением TCP на сервере Raspberry Pi (сервер на ПК) с PPP (протокол Point-Point Protocol) с использованием модема LTE. Я использовал программу C с сокетами, проверяя ответ системного вызова. Я хотел проверить, как сокет работает в плохой зоне покрытия, поэтому я сделал несколько тестов, удалив антенну.TCP-сокеты в C с плохой сетью

Я следовал следующие шаги:

  1. подключиться к серверу -> OK
  2. Начать отправку данных (запись системного вызова) -> OK (я также проверить на сервере)
  3. Я снял антенну LTE модема (Там нет сети, он не может сделать пинг)
  4. Продолжить отправку данных (написать системный вызов) -> OK (сервер не получает anyth ING !!!)
  5. Он закончил передачу данных и закрытый сокет ->OK (соединение все еще открыто, и нет никаких данных, так как антенна была удалена)
  6. Программы была закончена
  7. я снова
  8. поставил антенну

Спустя некоторое время данные были загружены и соединение закрыто. Но я сделал еще один тест, выполнив следующие шаги, но с дополнительными данными, и он не загрузил эти данные ...

Я не знаю, есть ли способ гарантировать, что данные, записанные на сервер TCP, будут получены сервером (Я думал, что уровень TCP обеспечил это ...). Я мог бы сделать это вручную, используя ACK, но я предполагаю, что это должен быть лучший способ сделать.

Отправка часть кода:

while(i<100) 
    { 
     sprintf(buf, "Message %d\n", i); 
     Return = write(Sock_Fd, buf, strlen(buf)); 
     if(Return!=strlen(buf)) 
     { 
      printf("Error sending data to TCP server. \n"); 
      printf("Error str: %s \n", strerror(errno)); 
     } 
     else 
     { 
      printf("write successful %d\n", i); 
      i++; 
     } 
     sleep(2); 
    } 

Большое спасибо за вашу помощь.

+0

вы используете неблокирующие сокеты? Как вы пишете данные и проверяете результаты? Можете ли вы попробовать создать [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve) клиентской программы и показать нам? –

+0

Я использую режим по умолчанию, режим блокировки, который я предполагаю (когда я подключаюсь к серверу, он ждет, пока не будет установлено соединение). –

ответ

4

write() -syscall возвращает true, так как ядро ​​буферизует данные и помещает их в очередь очереди. Он удаляется из этой очереди, когда данные были отправлены и, выделенных от партнера. Когда OutQueue будет заполнен, блокировка write будет заблокирована.

Чтобы определить, не были ли данные, полученные от сверстников, не были оценены сверстником, вы должны посмотреть на размер перепродажи.В Linux, вы можете использовать ioctl() для этого:

ioctl(fd, SIOCOUTQ, &outqlen); 

Однако, это было бы более чистыми и портативными использовать внутриполосный метод для определения, если данные были получены.

+0

Что такое «встроенный метод»? Я проверил в google, но я не нашел никакого ясного объяснения. –

+2

@JulenUranga Это означает, что подтверждение отправляется через само соединение tcp. Клиент: «DO STH» - сервер: «DONE». – Ctx

1

TCP/IP - довольно примитивная технология. Интернет может показаться новым, но это действительно антикварный материал. TCP необходим, потому что IP дает почти никаких гарантий, но TCP фактически не добавляет много гарантий. Его главная функция - превратить протокол пакета в протокол потока. Это означает, что TCP гарантирует порядок байтов; никакие байты не выйдут из строя. Не рассчитывайте больше на это.

Вы видите, что протоколы поверх TCP добавляют дополнительные проверки. Например. HTTP имеет известные коды ошибок HTTP, именно потому, что он не может полагаться на состояние ошибки из TCP. Возможно, вам придется сделать то же самое - или вы можете рассмотреть возможность внедрения своей службы в качестве службы HTTP. «RESTful» относится к методологии проектирования API, которая внимательно следит за философией HTTP; это может иметь отношение к вам.

1

Короткий ответ на Ваш 4-й и 5-й темы был взят в качестве ярлыка из this answer (читать весь ответ, чтобы получить больше информации)

Гнездо имеет буфер передачи и, если вызов посыла (), это не означает, что запрошенные данные действительно были отправлены, это означает, что данные были добавлены в буфер отправки. Для сокетов UDP данные обычно отправляются довольно скоро, если не сразу, но для сокетов TCP может быть относительно длинная задержка между добавлением данных в буфер отправки и реализацией TCP-данных, которые действительно отправляют эти данные. В результате, когда вы закрываете сокет TCP, все еще могут быть ожидающие данные в буфере отправки, который еще не отправлен, но ваш код считает его отправленным, поскольку вызов send() преуспел. Если реализация TCP немедленно закрыла сокет по вашему запросу, все эти данные будут потеряны, и ваш код даже не узнает об этом. TCP считается надежным протоколом, и потеря данных точно так же не очень надежна. Вот почему сокет, у которого все еще есть данные для отправки, переходит в состояние, называемое TIME_WAIT, когда вы его закрываете. В этом состоянии он будет ждать до тех пор, пока все ожидающие данные не будут успешно отправлены или пока не будет достигнут тайм-аут, и в этом случае сокет будет принудительно закрыт.

Количество времени, в течение которого ядро ​​будет ждать до его закрытия, независимо от того, имеет ли он еще ожидающие данные отправки или нет, называется Linger Time.

КСТАТИ: этот ответ также относится к docs, где вы можете получить более подробную информацию

+0

«Если реализация TCP немедленно закрыла сокет по вашему запросу, все эти данные будут потеряны». Что это значит? Сервер закрывает соединение или клиент закрывает сокет? Или оба? –

+1

@JulenUranga Это означает, что реализация по умолчанию не приведет к немедленному закрытию соединения: он попытается отправить все данные, все еще присутствующие в буфере, если они есть, а затем попытается закрыть сокет _gracefully_. Но если вы предпочитаете немедленно закрыть сокет ** (например, отключив время _Linger Time_), он будет закрыт _forcefully_, что означает, что все ожидающие данные в буфере будут проигнорированы и соединение немедленно будет закрыто. –

Смежные вопросы