Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Фрагментация TCP


Автор: REZiaMIX 29.11.2008, 02:26
Все говорят , что в TCP пакет может прийти как угодно , т.е. разбит на части. 
Часто ли Вы встречали это на практике , и каковы условия такого поведения?
Надо ли программно как-то обрабатывать фрагментацию?(не превышать MTU например)

В вики написано : 
Цитата

В отличие от UDP, гарантирует, что приложение получит данные точно в такой же последовательности, в какой они были отправлены, и без потерь.

Так ли это?

Условия:
Клиент и сервер могут находится между большим кол-вом маршрутизаторов.

Всем заранее спасибо за ответы.

Автор: J0ker 29.11.2008, 05:55
Цитата(REZiaMIX @  29.11.2008,  02:26 Найти цитируемый пост)
Все говорят , что в TCP пакет может прийти как угодно , т.е. разбит на части.

нет
смысл в том, что разбиение потока на пакеты при отправлении чаще всего от вас не зависит, а зависит от настроек стека протоколов

Цитата(REZiaMIX @  29.11.2008,  02:26 Найти цитируемый пост)
Часто ли Вы встречали это на практике

постоянно

Цитата(REZiaMIX @  29.11.2008,  02:26 Найти цитируемый пост)
и каковы условия такого поведения

настройки системы с которой отправляются данные плюс естественное ограничение накладываемое протоколами

Цитата(REZiaMIX @  29.11.2008,  02:26 Найти цитируемый пост)
Надо ли программно как-то обрабатывать фрагментацию?(не превышать MTU например)

в общем случае нет

Цитата(REZiaMIX @  29.11.2008,  02:26 Найти цитируемый пост)
Так ли это?

абсолютно

Автор: REZiaMIX 29.11.2008, 17:20
Т.е мне надо просто забивать на расклеенные пакеты , и обрабатывать только правильно пришедшие?

Автор: Lazin 29.11.2008, 18:03
нет, если ты принимаешь данные синхронно, то тебе будет приходить все сразу(то что уже получено от сервера), например сервер отправляет данные, блоками по 0х1000 байт, тогда ты просто передешь в ф-ю recv указатель на принимающий буфер и говоришь что нужно принять 0x1000 байт если данные уже получены, то ф-я просто скопирует их в  буфер, если нет, то она подождет пока они не прийдут.
если принимаешь данные асинхронно, то ты будешь получать не сразу столько, сколько попросишь, а столько, сколько уже пришло, а приходить оно может по частям и тебе нужно будет эти части объединять... как-то так smile 

Автор: J0ker 29.11.2008, 18:30
Цитата(Lazin @ 29.11.2008,  18:03)
нет, если ты принимаешь данные синхронно, то тебе будет приходить все сразу(то что уже получено от сервера), например сервер отправляет данные, блоками по 0х1000 байт, тогда ты просто передешь в ф-ю recv указатель на принимающий буфер и говоришь что нужно принять 0x1000 байт если данные уже получены, то ф-я просто скопирует их в  буфер, если нет, то она подождет пока они не прийдут.
если принимаешь данные асинхронно, то ты будешь получать не сразу столько, сколько попросишь, а столько, сколько уже пришло, а приходить оно может по частям и тебе нужно будет эти части объединять... как-то так smile

Lazin, не вводи человека в заблуждение
синхронная и асинхронная ОБРАБОТКА никакого отношения к recv не имеет
сервер не отправляет данные блоками - он отправляет поток
то, что сервер вызвал функцию send на 1000 байт не означает что данные будут запихнуты в один IP пакет - они могут быть как угодно фрагментированы на этапе отправки
и функция recv никогда не ждет, пока придет весь размер, указанный в размере буфера - она примет сколько есть на данный момент - тут существует только различие в блокирующем сокете и не блокирующем - блокирующий заблокируется если данный вообще нет и разблокируется если будет хотя-бы один байт (или закрывающий соединение пакет), а не блокирующий если нет данных просто выйдет со статусом ошибки EWOULDBLOCK

Автор: REZiaMIX 29.11.2008, 18:32
Цитата(Lazin @ 29.11.2008,  18:03)
нет, если ты принимаешь данные синхронно, то тебе будет приходить все сразу(то что уже получено от сервера), например сервер отправляет данные, блоками по 0х1000 байт, тогда ты просто передешь в ф-ю recv указатель на принимающий буфер и говоришь что нужно принять 0x1000 байт если данные уже получены, то ф-я просто скопирует их в  буфер, если нет, то она подождет пока они не прийдут.
если принимаешь данные асинхронно, то ты будешь получать не сразу столько, сколько попросишь, а столько, сколько уже пришло, а приходить оно может по частям и тебе нужно будет эти части объединять... как-то так smile

Т.е. если я заказываю асинхронно прием 512 байт данных , то вполне может прийти меньше?

Автор: J0ker 29.11.2008, 18:35
Цитата(REZiaMIX @ 29.11.2008,  17:20)
Т.е мне надо просто забивать на расклеенные пакеты , и обрабатывать только правильно пришедшие?

вам нужно собирать поток
все пришедшие пакеты ПРАВИЛЬНЫ - они просто разбиты на несколько вызовов функции recv
поймите - в TCP НЕТ пакетов - это поток, просто он на принимающей стороне появляется очень медленно (по сравнению с возможностью обработки) - и его надо ждать путем множественного вызова recv - как только вы СОБЕРЕТЕ кусок который можете обработать - вы его обрабатываете и собираете следующий кусок

Добавлено через 1 минуту и 9 секунд
Цитата(REZiaMIX @ 29.11.2008,  18:32)
Цитата(Lazin @ 29.11.2008,  18:03)
нет, если ты принимаешь данные синхронно, то тебе будет приходить все сразу(то что уже получено от сервера), например сервер отправляет данные, блоками по 0х1000 байт, тогда ты просто передешь в ф-ю recv указатель на принимающий буфер и говоришь что нужно принять 0x1000 байт если данные уже получены, то ф-я просто скопирует их в  буфер, если нет, то она подождет пока они не прийдут.
если принимаешь данные асинхронно, то ты будешь получать не сразу столько, сколько попросишь, а столько, сколько уже пришло, а приходить оно может по частям и тебе нужно будет эти части объединять... как-то так smile

Т.е. если я заказываю асинхронно прием 512 байт данных , то вполне может прийти меньше?

см. выше - нет никакого "синхронно-асинхронно"

Автор: REZiaMIX 29.11.2008, 18:38
Хм , читаю MSDN: 
Цитата

MSG_WAITALL    The receive request will complete only when one of the following events occurs:

    * The buffer supplied by the caller is completely full.
    * The connection has been closed.
    * The request has been canceled or an error occurred.

Note that if the underlying transport does not support MSG_WAITALL, or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP. Also, if MSG_WAITALL is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then this call will fail with WSAEOPNOTSUPP. This flag is not supported on datagram sockets or message-oriented CO sockets.

Т.е. с этим флагом пакет по идее должен прийти полностью , как заказанно?!?!?.
Только если сокет в блокирующем режиме ...

Не пойму , кто прав кто нет.

Автор: J0ker 29.11.2008, 18:51
Цитата(REZiaMIX @  29.11.2008,  18:38 Найти цитируемый пост)
Т.е. с этим флагом пакет по идее должен прийти полностью , как заказанно?!?!?.
Только если сокет в блокирующем режиме ...

забудьте про пакеты
этот флаг указывает блокирующему сокету сидеть в recv пока буфер который вы ему передали не будет полностью заполнен (либо не случится других неприятностей)
к пакетам это отношения не имеет
еще раз объясняю
если вы на одной стороне вызвали send на 1000 байт, то это не означает, что уйдет пакет на 1000 байт - может уйти десять пакетов разной длины - это решает стек протоколов
если вы на принимающей стороне вызвали recv на 1000 байт на блокирующей сокет - то recv выйдет с ЛЮБЫМ количеством принятых байт меньше или равно 1000, либо будет заблокирован если вы указали MSG_WAITALL пока не заполнит 1000 байт - но это не имеет отношения к пакетам

Автор: REZiaMIX 29.11.2008, 19:01
Цитата(J0ker @ 29.11.2008,  18:51)
забудьте про пакеты
этот флаг указывает блокирующему сокету сидеть в recv пока буфер который вы ему передали не будет полностью заполнен (либо не случится других неприятностей)
к пакетам это отношения не имеет
еще раз объясняю
если вы на одной стороне вызвали send на 1000 байт, то это не означает, что уйдет пакет на 1000 байт - может уйти десять пакетов разной длины - это решает стек протоколов
если вы на принимающей стороне вызвали recv на 1000 байт на блокирующей сокет - то recv выйдет с ЛЮБЫМ количеством принятых байт меньше или равно 1000, либо будет заблокирован если вы указали MSG_WAITALL пока не заполнит 1000 байт - но это не имеет отношения к пакетам

Не пакет , а скажем целиковый буффер отправленный другой стороной) 
Вот это мне и требовалось услышать

Автор: J0ker 29.11.2008, 19:12
тока не забудьте, что с разрешенными сигналами или OOB пакетами recv может наплевать на MSG_WAITALL

Автор: REZiaMIX 29.11.2008, 19:22
Цитата(J0ker @ 29.11.2008,  19:12)
тока не забудьте, что с разрешенными сигналами или OOB пакетами recv может наплевать на MSG_WAITALL

Знаю. Спасибо)

Автор: MAKCim 30.11.2008, 11:15
Цитата(J0ker @  29.11.2008,  18:30 Найти цитируемый пост)
блокирующий заблокируется если данный вообще нет и разблокируется если будет хотя-бы один байт

ну не совсем
точнее количество байт, нужное для разблокирования recv, не фиксировано и может быть установлено
по-умолчанию 1 байт  smile 


Автор: Олег2005 30.11.2008, 14:39
Цитата(MAKCim @  30.11.2008,  10:15 Найти цитируемый пост)
не фиксировано и может быть установлено
по-умолчанию 1 байт  smile 

Может быть? Оно уже установлено в 1 байт:
Цитата
SO_RCVLOWAT, SO_SNDLOWAT 
Этими опциями регулируется минимальное количество данных в буфере приема/передачи, на которое реагирует функция select(). Для приемного буфера модуля TCP по умолчанию это 1 байт. Для буфера передачи - это минимально допустимое количество свободного пространства, когда сокет будет готов для передачи, для TCP-сокетов это обычно 2048.

Так как посылки keepalive содержат ровно 1 байт smile 

Автор: MAKCim 30.11.2008, 18:52
Цитата(Олег2005 @  30.11.2008,  14:39 Найти цитируемый пост)
Может быть? Оно уже установлено в 1 байт:

так я не понял, где я не прав?  smile 

Автор: Олег2005 30.11.2008, 21:33
Цитата(MAKCim @  30.11.2008,  10:15 Найти цитируемый пост)
может быть установлено
по-умолчанию 1 байт  smile 

Не может - а уже установлено smile 

Автор: MAKCim 30.11.2008, 22:34
Цитата(Олег2005 @  30.11.2008,  21:33 Найти цитируемый пост)
Не может - а уже установлено

так я и сказал, что по-умолчанию 1
но в общем случае это не фиксированная константа
значение можно менять, в этом смысле

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)