UDP: прослушивание одного и того же порта для двух разных многоадресных потоков - PullRequest
5 голосов
/ 13 декабря 2011

Мне нужно прослушать 2 разные группы многоадресной рассылки, используя один и тот же порт. Program A будет прослушивать с 230.0.0.1 и Program B с 230.0.0.2. Обе многоадресные группы используют один и тот же port 2000, и я не могу его контролировать.

Когда я запускаю свои программы, я получаю оба многоадресных потока в каждой программе, то есть оба пакета данных, транслируемые на 230.0.0.1 и 230.0.0.2. Я подозреваю, что проблема связана с общим портом. Это код, который я использую для подписки на многоадресную рассылку:

if( (sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 ) {
  perror("socket");
  return -1;
}

if( setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0 ) {
  perror("setsockopt SO_REUSEADDR");
  return -1;
}

memset(&in_addr, 0, sizeof(in_addr));
in_addr.sin_family = AF_INET;
in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
in_addr.sin_port = htons(2000);
if( bind(sd, (struct sockaddr*)&in_addr, sizeof(in_addr)) < 0 ) {
  perror("bind");
  return -1;
}

memset(&req, 0, sizeof(req));
inet_aton(intfc_ip, &req.imr_interface);
inet_aton("230.0.0.1", &req.imr_multiaddr);
if( setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req)) < 0 ) {
  perror("setsockopt IP_ADD_MEMBERSHIP");
  return -1;
}

recv()...

Как я могу отфильтровать определенную группу многоадресной рассылки в каждой программе?

Ответы [ 4 ]

4 голосов
/ 13 декабря 2011

Если вы измените

in_addr.sin_addr.s_addr = htonl(INADDR_ANY);

на

inet_aton(<your wanted IP address>, &in_addr.sin_addr.s_addr);

, вы можете добиться большего успеха.

(И если вы измените свою программу для работы с getaddrinfo(), вы делаете это на будущее.)

3 голосов
/ 13 декабря 2011

«Соединиться» может быть то, что вам нужно в конце концов. Как правило, для подключения сокетов TCP на странице руководства также предлагается использовать ее для фильтрации пакетов UDP с других адресов:

Со страницы руководства, размещенной здесь :

Если сокет sockfd имеет тип SOCK_DGRAM, то адрес - это адрес какие дейтаграммы отправляются по умолчанию, и единственный адрес, с которого датаграммы получены.

2 голосов
/ 13 декабря 2011

Проблема с кодом сокета состоит в том, что «recvfrom» даст вам только адрес источника, с которого пакет был отправлен. Он не сообщает вам IP-адрес того, куда был отправлен пакет. Вы хотите иметь возможность проверять адрес назначения UDP-пакета, чтобы можно было отфильтровывать пакеты, отправленные на IP-адреса многоадресной рассылки, которые вас не интересуют.

Существует опция сокета, которую вы можете установить, а затем использовать recvmsg вместо recv или recvfrom для получения IP-адреса назначения, на который был отправлен пакет.

1) Используйте setsockopt с IP_PKTINFO, чтобы включить получение IP-адреса назначения, переданного на уровень приложения для данных, полученных в сокете.

int enable = 1;
setsockopt(sock, IPPROTO_IP , IP_PKTINFO , &enable, sizeof(enable));

2) Используйте recvmsg вместо recvfrom (или recv), чтобы получить адрес назначения, на который был отправлен пакет UDP. У меня есть вспомогательная функция с именем "recvfromex", которая оборачивает recvmsg и отражает функциональность recvfrom - ожидайте, что у нее есть дополнительный параметр для вызывающей стороны, чтобы получить IP-адрес назначения пакета.

Это немного ветрено, но вы можете посмотреть на мой код C ++ из моего проекта на github и взять то, что вам нужно.

Посмотрите на функцию recvfromex здесь

Больше примеров кода для вызова setsockopt здесь (обратитесь к функции "EnablePktInfo", чтобы узнать, как использовать вызов setsockopt с IP_PKTINFO). Также содержит расширения для IPV6 и BSD.

1 голос
/ 02 мая 2015

(из ответа из Получение нескольких многоадресных каналов на одном и том же порту - C, Linux )

Страница управления ip (7) опишите возможное решение:

IP_MULTICAST_ALL (начиная с Linux 2.6.31)
Этот параметр можно использовать для изменения политики доставки многоадресных сообщений в сокеты, связанные с подстановочным адресом INADDR_ANY.Аргумент является логическим целым числом (по умолчанию 1).Если установлено значение 1, сокет будет получать сообщения от всех групп, которые были объединены глобально во всей системе.В противном случае он будет доставлять сообщения только из групп, которые были явно присоединены (например, с помощью опции IP_ADD_MEMBERSHIP) в этот конкретный сокет.

Затем вы можете активировать фильтр для получения сообщений из объединенных групп, используя:

int mc_all = 0;
if ((setsockopt(sock, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) {
    perror("setsockopt() failed");
}
...