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


Автор: Artemon 6.2.2009, 19:33
Стоит задача написать многопоточный UDP сервер (именно UDP)

Много клиентов и каждый шлет на сервер сложную структуру данных, а затем сервер отвечает на это сообщение.

Если я буду в цикле через recvfrom принимать данные, то наткнусь на следующую ситуацию:

Пришла какая-то часть данных одного клиента, а за ней часть данных от другого клиента и не будет возможности их отделить.

Пришла в голову мысли получать IP пакет и собирать из них полное сообщение, а уж затем обрабатывать.

У кого какие мысли ?

Автор: SVN74 6.2.2009, 22:07
UDP - ненадежный протокол и слать через него "сложную структуру" нежелательно. Почему бы не использовать TCP ? Конечно полной 100% -ой  гарантии нет, но все же надежней будет ... 

Автор: Олег2005 7.2.2009, 11:15
Цитата(Artemon @  6.2.2009,  18:33 Найти цитируемый пост)
Если я буду в цикле через recvfrom принимать данные, то наткнусь на следующую ситуацию:
Пришла какая-то часть данных одного клиента, а за ней часть данных от другого клиента и не будет возможности их отделить.
Пришла в голову мысли получать IP пакет и собирать из них полное сообщение, а уж затем обрабатывать.

Надо представлять логику предачи по UDP и работы recvfrom ()
Передатчик шлет одну датаграмму, в которой есть все что надо.
Приемник с помощью recvfrom () получает ту полную датаграмму, которую послал передатчик.
Он никогда не получит ее часть. Только всю целиком - но только данные. Вся адресная часть останется в модуле стека.
Поэтому после recvfrom() следует выполнить getpeername() и получить адрес клиента, с которого пришел ответ, завести список всех клиентов и соединять данные по отдельным клиентам.
Примерно так   

Автор: Artemon 7.2.2009, 20:31
Цитата

UDP - ненадежный протокол и слать через него "сложную структуру" нежелательно. Почему бы не использовать TCP ? Конечно полной 100% -ой  гарантии нет, но все же надежней будет ... 


Да, TCP очень четко работает и нет никаких потерь + знаю от какого клиента идут пакеты,
но в моей задаче получается так, что заголовок TCP пакета получается еще больше чем сами данные, поэтому КПД очень низок. Из-за этой причины решил использовать UDP.

Цитата

Приемник с помощью recvfrom () получает ту полную датаграмму, которую послал передатчик.
....


Хочешь сказать, что если два клиента примерно в одно время пошлют по 1600 байт информации - есть гарантия, что придет полностью один из блоков в 1600 байт, а затем следующий блок в 1600 байт, но ни как не перемешанная информация ?

Обратите внимание, я не спроста написал 1600, в большинстве сетей MTU ~ 1500.

Автор: Олег2005 9.2.2009, 00:20
Цитата(Artemon @  7.2.2009,  19:31 Найти цитируемый пост)
атите внимание, я не спроста написал 1600, в большинстве сетей MTU ~ 1500. 

Первый же маршрутизатор фрагментирует ваш  UDP - пакет - на 2 IP- пакета. Модуль IP приемника дефрагментирует и выдаст на гора те же 1600 байт. Но если один фрагмент придет не вовремя - весь пакет отбросится - или будет обрезан - это зависит от конкретной реализации стека. 

Автор: Artemon 9.2.2009, 11:48
Плохо конечно что не принятые данные  обрезаются, это говорит о том, что мы не можем использовать разный размер буфера.

Думаю остается способ собирать IP пакеты воедино, а затем обрабатывать,

кто-нибудь делал подобное ? 

Автор: Comm 19.2.2009, 08:50
Цитата

Много клиентов и каждый шлет на сервер сложную структуру данных

А почему бы в этой структуре данных заодно и не послать  идентификатор клиента и пакета.. Этим  можно частично побороть не надежность UDP протокола.
Допустим пришел пакет с данными от клиента с идентификатором пакета "2" сервер делает проверку есть ли от этого клиента пакет номер "1" если нет то шлет запрос на повторную отправку первого пакета итд. итп.

Автор: Олег2005 19.2.2009, 12:52
Цитата(Artemon @  9.2.2009,  10:48 Найти цитируемый пост)
что мы не можем использовать разный размер буфера.

Какой буфер вы имеете в виду?
Обрезка идет в приемном буфере модуля UDP - а его можно выставить существенно большим, чем 64 к - опция SO_SNDBUF 
Как уже говорилось, опции SO_RCVBUF и SO_SNDBUF позволяют приложению изменять размеры буферов, заданные по умолчанию, которые для различных реализаций очень отличаются. В Беркли-реализациях по умолчанию используются буфера отправки и приема размером в 4096 байт, более современные системы используют буфера размером от 8192 до 61 440 байт. Размер буфера отправки UDP по умолчанию обычно около 9000 байт, если узел поддерживает NFS; а размер приемного буфера UDP — около 40 000 байт, а максимальное значение по умолчанию может достигать и 250Кб.

Автор: kolobok0 16.3.2009, 19:09
Цитата(Artemon @ 6.2.2009,  19:33)
Стоит задача написать многопоточный UDP сервер (именно UDP)...

Вам уже написали решение.

1) собирать ничего не нуна. пакет либо прийдёт весь либо не прийдёт - третьего не дано. (CRC считаеться по всему пакету, дефрагментация идёт на IP уровне в толще самого стэка, вы об этом нифига не разумете если не сами автор этого стэка)
2) протокол TCP использует заголовок достаточно маленький при больших объёмах. Шлите не 50 байт а 50 мегабайт и будет вам копейки. Либо держите канал открытым.
3) Если всё таки UDP - тут уже правильно всё сказали. используйте свои маркеры сессий, пользователя и прочей лабуды. Очень рулит при таком подходе - юзанье "чёрного ящика" на стороне клиента от сервера. а сервер трактует этот "чёрный ящик" как свои данные..Нечто аля куки или сешшион под HTTP..

удачи Вам
(круглый)

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