Модераторы: feodorv
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> recvfrom ничего не принимает без bind 
:(
    Опции темы
Apel
Дата 19.11.2010, 23:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 40
Регистрация: 30.8.2006

Репутация: нет
Всего: нет



некий софт постоянно отправляет широковещательные udp на один определённый Port. Я их хочу ловить и делаю так:

Код

    WSADATA WSAData = {0};
    if(WSAStartup(0x0202, &WSAData)) throw e();

    Peer.sin_family = AF_INET;
    Peer.sin_addr.s_addr = htonl(INADDR_ANY);
    Peer.sin_port = htons(Port);

    PeerSize = sizeof(Peer);

    
    if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) throw e();
    //if(bind(s, (SOCKADDR *)&Peer, sizeof(Peer)) == SOCKET_ERROR) throw e();
    
    recvfrom(s, Buffer, Size, 0, (SOCKADDR *)&Peer, &PeerSize);

    if(closesocket(s) == SOCKET_ERROR) throw e();
    if(WSACleanup() == SOCKET_ERROR) throw e();



если не делать вызов bind, кажется, ловится мусор или этот мусор изначально находится в буфере. с bind ловится пакет как надо. не встречал в шаблонах удп клиента использование bind, но там сначала вызывается sendto (которая делает что-то что и bind и connect). Если я сначала вызываю sendto без bind ничего не меняется. В чём тут дело?
PM MAIL   Вверх
null56
Дата 20.11.2010, 03:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: нет
Всего: 12



Я попробую предположить по мануалам, ибо не имею у себя винды, чтобы проверить....
Для начала, что такое bind
http://msdn.microsoft.com/en-us/library/ms...28VS.85%29.aspx
Функция bind организует фильтр пакетов, иными словами, из всех пришедших пакетов в систему твоему сокету буду доставлены только пакеты с определенным адресом и определенным портом, которыми ты заполнил структуру
Код

__in  const struct sockaddr *name,

Далее функция socket
http://msdn.microsoft.com/en-us/library/ms...28VS.85%29.aspx
Выступает тоже в роли фильтра, ибо ты сразу говоришь, что этот сокет будет работать только с датаграммами протокола udp, сюда система пришлет все пакеты, идущие по данному протоколу....
Теперь, если я ничего не путаю, не задав функции connect()/bind(), в твой сокет, без вызова функции bind (то есть привязки к определенному, нужному тебе порту), тебе будут сыпаться все пришедшие в систему датаграммы по протоколу udp.
Внимание: я уверен, что сказанное мною справедливо для сырых сокетов (RAW), надеюсь, гуру форума поправят меня, если я ошибаюсь
Теперь предположу твою ошибку, я думаю она здесь
Код

    recvfrom(s, Buffer, Size, 0, (SOCKADDR *)&Peer, &PeerSize);

ты надеешься, что параметр Peer отфильтрует пакеты на нужный тебе порт??? если да то это не так, посмотри на прототип функции
http://msdn.microsoft.com/en-us/library/ms...28VS.85%29.aspx
Код

int recvfrom(
  __in         SOCKET s,
  __out        char *buf,
  __in         int len,
  __in         int flags,
  __out        struct sockaddr *from,
  __inout_opt  int *fromlen
);

слово __out перед параметром from, говорит, что читать данные с твоего параметра никто не собирается, его собираются заполнить. Заполнят его как раз данными отправителя (адресом и портом). Доступ к полям структуры у тебя есть, номер порта (применив преобразование из сетевого порядка байтов) ты узнать можешь, а соответсвенно и отфильтровать тоже
Код

//...
while(...)
{
   if (recvfrom(s, Buffer, Size, 0, (SOCKADDR *)&Peer, &PeerSize) && ntohl(Peer.sin_port) == Port)
   {
      // делай чо хош с пакетом
   }
}
//...

Я надеюсь, что не дезинформировал тебя ложной информацией, надеюсь гуру в сетях меня поправят

Добавлено через 13 минут и 34 секунды
да, и хорошо бы проверять возвращаемое значение функции recvfrom на наличие ошибки

Это сообщение отредактировал(а) null56 - 20.11.2010, 03:35
PM MAIL   Вверх
Олег2005
Дата 20.11.2010, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

Репутация: 6
Всего: 11



Ваша ошибка состоит в нарушении логики модели клиент/сервер
По этой логике - сначала запрос клиента - потом ответ сервера.

Запрос - это функция sendto().
Именно при вызове этой функции ядро системы динамически присваивает приложению значение порта. Именно на этот порт будут потом приходить ответы сервера.
Если не запускать sendto(), то этого не происходит - а функция recvfrom() - не предназначена для выполнения этого действия.
Так что если клиент не начинает своей работы с endto(), то bind() - обязателен.

Это сообщение отредактировал(а) Олег2005 - 20.11.2010, 12:08
PM MAIL WWW MSN   Вверх
Apel
Дата 20.11.2010, 18:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 40
Регистрация: 30.8.2006

Репутация: нет
Всего: нет



Спасибо за разъяснение, я так примерно и предполагал, но я не понимаю почему если вызвать вместо bind 

Код

sendto(s, "test", 5, 0, (SOCKADDR *)&Peer, sizeof(Peer));


а затем  recvfrom, то всё равно Peer не привязывается к сокету. А про in-out параметры я знаю, просто привёл код только с bind.

Это сообщение отредактировал(а) Apel - 21.11.2010, 00:43
PM MAIL   Вверх
Олег2005
Дата 21.11.2010, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 421
Регистрация: 26.5.2005
Где: Рига Латвия

Репутация: 6
Всего: 11



Видите ли, peer  у вас - это - удаленный сокет - и соответственно у вас есть его адрес - это типа адреса получателя на почтовом конверте.
bind() - предназначен для связи с локальным (местным) сокетом (мы его так сказать не видим - а система его создает) - и привязывает местный сетевой интерфейс, известный системе, а также порт (выделенный клиенту динамически) - к дескриптору этого локального сокета.

Это сообщение отредактировал(а) Олег2005 - 21.11.2010, 19:09
PM MAIL WWW MSN   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1121 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.