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

У меня есть приложение, которое получает данные из нескольких источников многоадресной передачи на том же порте. Я могу получить данные. Однако я пытаюсь объяснить статистику каждой группы (т.е. полученный msgs, полученные байты), и все данные становятся перепутанными. Кто-либо знает как к решенному эта проблема? Если я пытаюсь посмотреть на адрес отправителя, это не групповой адрес, а скорее IP передающей машины.

Я использую следующие опции сокета:

struct ip_mreq mreq;         
mreq.imr_multiaddr.s_addr = inet_addr("224.1.2.3");         
mreq.imr_interface.s_addr = INADDR_ANY;         
setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

и также:

setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));
13
задан Cœur 21 May 2018 в 11:05
поделиться

4 ответа

Адрес многоадресной рассылки будет адресом получателя, а не адресом отправителя в пакете. Посмотрите IP-адрес получателя.

0
ответ дан 1 December 2019 в 20:42
поделиться

[Отредактировано, чтобы уточнить, что bind () на самом деле может включать адрес многоадресной рассылки.]

Таким образом, приложение присоединяется к нескольким группам многоадресной рассылки и получает сообщения, отправленные любому из них, на тот же порт. SO_REUSEPORT позволяет привязать несколько сокетов к одному порту. Помимо порта, bind () нужен IP-адрес. INADDR_ANY - это адрес для приема всей почты домена, но также может использоваться IP-адрес, включая многоадресный. В этом случае в сокет будут доставлены только пакеты, отправленные на этот IP-адрес. Т.е. вы можете создать несколько сокетов, по одному для каждой многоадресной группы. bind () каждый сокет к (group_addr, port) И присоединяется к group_addr. Тогда данные, адресованные разным группам, будут отображаться в разных сокетах, и вы сможете так их различать.

Я проверил, что во FreeBSD работает следующее:

#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, const char *argv[])
{
    const char *group = argv[1];

    int s = socket(AF_INET, SOCK_DGRAM, 0);
    int reuse = 1;
    if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
        fprintf(stderr, "setsockopt: %d\n", errno);
        return 1;
    }

    /* construct a multicast address structure */
    struct sockaddr_in mc_addr;
    memset(&mc_addr, 0, sizeof(mc_addr));
    mc_addr.sin_family = AF_INET;
    mc_addr.sin_addr.s_addr = inet_addr(group);
    mc_addr.sin_port = htons(19283);

    if (bind(s, (struct sockaddr*) &mc_addr, sizeof(mc_addr)) == -1) {
        fprintf(stderr, "bind: %d\n", errno);
        return 1;
    }

    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(group);
    mreq.imr_interface.s_addr = INADDR_ANY;
    setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

    char buf[1024];
    int n = 0;
    while ((n = read(s, buf, 1024)) > 0) {
        printf("group %s fd %d len %d: %.*s\n", group, s, n, n, buf);
    }
}

Если вы запустите несколько таких процессов для разных многоадресных адресов и отправите сообщение на один из адресов, только соответствующий процесс получит его. Конечно, в вашем случае вы, вероятно, захотите иметь все сокеты в одном процессе, и вам придется использовать select или poll или эквивалент, чтобы прочитать их все.

10
ответ дан 1 December 2019 в 20:42
поделиться

IIRC recvfrom() дает вам разные адреса/порты чтения для каждого отправителя.

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

0
ответ дан 1 December 2019 в 20:42
поделиться

Используйте setsockopt() и IP_PKTINFO или IP_RECVDSTADDR в зависимости от вашей платформы, предполагая IPv4. Это в сочетании с recvmsg() или WSARecvMsg() позволит вам найти исходный и адрес назначения каждого пакета.

Unix/Linux, обратите внимание, FreeBSD использует IP_RECVDSTADDR, в то время как оба поддерживают IP6_PKTINFO для IPv6.

Windows, также имеет IP_ORIGINAL_ARRIVAL_IF

5
ответ дан 1 December 2019 в 20:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: