Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

чтение UDP пакета по частям

67K
10 февраля 2011 года
nozog
4 / / 10.02.2011
Здравствуйте

Есть сообщение от клиента по UDP
что то типа такого
 
Код:
typedef struct{
 ush type;
 ush size;
 char data[size];
} Msg_t


делал как тут http://www.abc.se/~m6695/udp.html
но recvfrom() требует полный размер сообщения, а мне он не известен.

Вопрос:
Как серверу прочитать пришедшее сообщение от клиента по частям ?
(прочитать тип, прочитать размер, прочитать данные)
или как узнать размер пришедшего сообщения?

Спасибо.
278
10 февраля 2011 года
Alexander92
1.1K / / 04.08.2008
Возможно, не до конца понял суть вопроса, но пока проблемы не увидел. Исходя из определения Msg_t, вы должны прочитать Msg_t::type и Msg_t::size (это строго определенное количество байт, равное sizeof(Msg_t::type) и sizeof(Msg_t::size) соответственно). После этого вы спокойно читаете количество байт, равное size - хоть по частям, хоть единым блоком.

Код:
char msgTypeStr[4] = {'\0'};
char msgSizeStr[4] = {'\0'};
char buf[BUF_LEN] = {'\0'};
ush msgType = 0, msgSize = 0;

recvfrom(s, msgTypeStr, sizeof(Msg_t::type), 0, &si_other, &slen);
recvfrom(s, msgSizeStr, sizeof(Msg_t::size), 0, &si_other, &slen);

// convert msgTypeStr to msgType and msgSizeStr to msgSize here

ush commonReadBytesNum = 0;
ush currentReadBytesNum = recvfrom(s, BUF_LEN, 0, &si_other, &slen);
while ((currentReadBytesNum > 0) && (commonReadBytesNum <= msgSize)) {
  commonReadBytesNum += currentReadBytesNum;
  currentReadBytesNum = recvfrom(s, BUF_LEN, 0, &si_other, &slen);
}


P.S. Писал без проверки, за мелкие ошибки не обессудьте.
67K
10 февраля 2011 года
nozog
4 / / 10.02.2011
Цитата: Alexander92
Возможно, не до конца понял суть вопроса, но пока проблемы не увидел. Исходя из определения Msg_t, вы должны прочитать Msg_t::type и Msg_t::size (это строго определенное количество байт, равное sizeof(Msg_t::type) и sizeof(Msg_t::size) соответственно). После этого вы спокойно читаете количество байт, равное size - хоть по частям, хоть единым блоком.

Код:
char msgTypeStr[4] = {'\0'};
char msgSizeStr[4] = {'\0'};
char buf[BUF_LEN] = {'\0'};
ush msgType = 0, msgSize = 0;

recvfrom(s, msgTypeStr, sizeof(Msg_t::type), 0, &si_other, &slen);
recvfrom(s, msgSizeStr, sizeof(Msg_t::size), 0, &si_other, &slen);

// convert msgTypeStr to msgType and msgSizeStr to msgSize here

ush commonReadBytesNum = 0;
ush currentReadBytesNum = recvfrom(s, BUF_LEN, 0, &si_other, &slen);
while ((currentReadBytesNum > 0) && (commonReadBytesNum <= msgSize)) {
  commonReadBytesNum += currentReadBytesNum;
  currentReadBytesNum = recvfrom(s, BUF_LEN, 0, &si_other, &slen);
}


P.S. Писал без проверки, за мелкие ошибки не обессудьте.



А разьве после вызова recvfrom(s, msgTypeStr, sizeof(Msg_t::type), 0, &si_other, &slen);
с флагом 0 из приемного буфера убирается только то что вычитал а не все сообщение?

278
10 февраля 2011 года
Alexander92
1.1K / / 04.08.2008
Цитата:

разьве после вызова recvfrom(s, msgTypeStr, sizeof(Msg_t::type), 0, &si_other, &slen);
с флагом 0 из приемного буфера убирается только то что вычитал а не все сообщение?


Как мне помнится из моей собственной практики - нет. По крайней мере, никогда не сталкивался с каким-то другим поведением.
Вот, собственно, описание recvfrom().

67K
10 февраля 2011 года
nozog
4 / / 10.02.2011
Цитата: Alexander92
Как мне помнится из моей собственной практики - нет. По крайней мере, никогда не сталкивался с каким-то другим поведением.
Вот, собственно, описание recvfrom().




recvfrom(s, msgTypeStr, sizeof(Msg_t::type), 0, &si_other, &slen);
читает нормально, а далее
recvfrom(s, msgSizeStr, sizeof(Msg_t::size), 0, &si_other, &slen);
в msgSizeStr лежит тип сообщения
Похоже, что при чтении части остальные данные из сообщения теряются.

Да речь про Linux, если это имеет значение

278
10 февраля 2011 года
Alexander92
1.1K / / 04.08.2008
Я прошу прощения, дело в том, что я сам на 99% пишу под Windows, поэтому немного ошибся. Дело в том, что в Windows есть функция WSARecvFrom(), которая во многом идентична обычной recvfrom(), но при этом еще и поддерживает чтение UDP-датаграмм по частям. Поищите аналог этой функции под Linux (либо если здесь кто-то подскажет - тоже почитаю =)).
37K
10 февраля 2011 года
qbikk
40 / / 08.09.2010
возможно не то что надо , но если пригодится...)
я делал так: в структуре которую посылаю первая переменная является размер всей структуры. и размер этой переменной знаем....
далее сначала считываем только размер
 
Код:
k = recvfrom( s, &size, HEAD_SIZE, MSG_PEEK, (struct sockaddr *) c_addr, &len )

а параметр MSG_PEEK как раз говорит что после чтения все сообщение остается в стеке(и прочитаная часть тоже)
после чего мы уже знаем полный размер сообщения и уже считываем все сообщение полностью
как-то так)
278
11 февраля 2011 года
Alexander92
1.1K / / 04.08.2008
qbikk, насколько я понял из первого поста, формат сообщений от клиента предопределен, и его менять нельзя. Если это не так - соглашусь с вами на 100%, я не предлагал этот вариант только из изложенных соображений.
67K
11 февраля 2011 года
nozog
4 / / 10.02.2011
Цитата: qbikk
возможно не то что надо , но если пригодится...)
я делал так: в структуре которую посылаю первая переменная является размер всей структуры. и размер этой переменной знаем....
далее сначала считываем только размер
 
Код:
k = recvfrom( s, &size, HEAD_SIZE, MSG_PEEK, (struct sockaddr *) c_addr, &len )

а параметр MSG_PEEK как раз говорит что после чтения все сообщение остается в стеке(и прочитаная часть тоже)
после чего мы уже знаем полный размер сообщения и уже считываем все сообщение полностью
как-то так)



я про такой вариант думал
выполнить recvfrom() с флагом MSG_PEEK на размер type + size
далее recvfrom() с флагом 0 на весь размер
но дело в том что хотелось поле дата читать тоже частями
в соответствующие структуры а не выделять временный буфер

Не знаю можно так или нет но попробовал
выполнить recvfrom() с флагом MSG_PEEK на размер type + size
далее делать read() того что нужно,
но уже второй reda() возвращает размер меньше чем прошу прочитать
хотя размер буфера много больше размера сообщения
смотрел так: getsockopt ( sfd, SOL_SOCKET, SO_RCVBUF, &size, &sa_len)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог