recvfrom работает с INADDR_ANY, но указание определенного интерфейса не работает

Я написал программу, которая присоединяется к группе многоадресной рассылки источника и получает многоадресные пакеты udp:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <net/if.h>

typedef unsigned int        UINT32;

int join_ssm_group(int s, UINT32 group, UINT32 source, UINT32 inter) {
struct ip_mreq_source imr;
imr.imr_multiaddr.s_addr  = group;
imr.imr_sourceaddr.s_addr = source;
imr.imr_interface.s_addr  = inter;
return setsockopt(s, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *) &imr, sizeof(imr));
}

UINT32 LISTEN_INTERFACE = inet_addr("10.10.1.2");

int main(int argc, char *argv[]) {

if (argc<3) {
printf(" Use: %s <group> <source> <port>", argv[0]);
return 1;
}

//  Make socket
int sd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

struct sockaddr_in Sender;
socklen_t SenderAddrSize = sizeof( Sender );

struct sockaddr_in binda;

//  Bind it to listen appropriate UDP port
binda.sin_family = AF_INET;
binda.sin_port = htons( atoi(argv[3]));
= INADDR_ANY;
// binda.sin_addr.s_addr = LISTEN_INTERFACE;
bind(sd,(struct sockaddr*)&binda, sizeof(binda));

// Join to group
join_ssm_group( sd, inet_addr(argv[1]),
inet_addr(argv[2]),
INADDR_ANY );

char        buf[65536];
UINT32      seq;

while(1) {
printf("try receive\n");
int res=recvfrom(sd,(char*)buf,sizeof(buf),0, (struct sockaddr *)& Sender, &SenderAddrSize);
printf("received\n");
seq = *(UINT32*)buf;
printf("scr=:%12s;\tseq=%6d;\tlen=%4d\n", inet_ntoa(Sender.sin_addr), seq, res);
}

return 0;
}

Работает нормально, но учтите, что я использую binda.sin_addr.s_addr = INADDR_ANY;, netstat показывает это:

netstat -a | grep 16002
udp        0      0 0.0.0.0:16002           0.0.0.0:*

Когда я изменяю это на binda.sin_addr.s_addr = LISTEN_INTERFACE; программа перестает работать — не может получать пакеты, зависает в recvfrom, netstat показывает это:

netstat -a | grep 16002
udp        0      0 localhost.localdo:16002 0.0.0.0:*

В обоих случаях tcpdump показывает, что данные находятся в оперативном режиме, поэтому проблема в том, что я не могу получить данные на конкретном интерфейсе, только на ВСЕХ интерфейсах. Я использую RHEL 7, teaming, и LISTEN_INTERFACE — это IP-адрес соответствующей VLAN. Почему мой код не работает и как его устранить? Я не хочу использовать INADDR_ANY по соображениям производительности — прослушивание ВСЕХ интерфейсов было бы дороже, чем прослушивание определенного интерфейса.

обн передача LISTEN_INTERFACE обоим join_ssm_group и и binda.sin_addr.s_addr тоже не работает Кстати, аналогичная версия Windows такого кода работает на том же ПК под Windows Server 2008 R2, но не работает в RHEL 7. Думаю, мне стоит проверить это:

  • если RHEL 7 получает данные через интерфейс requreid на требуемый порт (ответ — да, подтверждено tcpdump)
  • если сокет прослушивает требуемый интерфейс на требуемом порту (ответ Да, подтверждено netstat?)
  • если оба ответа выше да, то как это возможно, что вызов recvfrom не получает данные?

Ну, наверное, этот вопрос больше о RHEL 7 сейчас, чем о c ++.

0

Решение

Когда вы присоединяетесь к группе многоадресной рассылки, вам нужно указать тот же интерфейс, который вы слушаете, или присоединиться к нему через все интерфейсы в цикле.

Однако прослушивание на всех интерфейсах является нормой. Это не «медленно» и «хорошая идея», если только у вас нет особых причин ограничивать тех, кто может подключиться.

1

Другие решения


По вопросам рекламы [email protected]