Размер буфера пользователя для приема многоадресных пакетов? - PullRequest
3 голосов
/ 25 октября 2019

приведенный ниже код взят из Git. Он присоединяется к многоадресной группе и получает пакеты.

Здесь мы зациклимся и получим данные в буфере с именем msgbuf:

while (1) 
{
    char msgbuf[MSGBUFSIZE];
    const int addrlen = sizeof(addr);
    const int nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *) &addr, &addrlen);

Как выбрать размер для буфера msgBuf? это просто должен быть максимальный размер пакета? Или мне нужно хранить несколько пакетов при обработке первого?

Полный код:

int main(int argc, char *argv[])
{
    if (argc != 3) {
       printf("Command line args should be multicast group and port\n");
       printf("(e.g. for SSDP, `listener 239.255.255.250 1900`)\n");
       return 1;
    }

    char* group = argv[1]; // e.g. 239.255.255.250 for SSDP
    int port = atoi(argv[2]); // 0 if error, which is an invalid port

    if(port <= 0)
    {
        perror("Invalid port");
        return 1;
    }


    // create what looks like an ordinary UDP socket
    //
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) 
    {
        perror("socket");
        return 1;
    }

    // allow multiple sockets to use the same PORT number
    //
    u_int yes = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &yes, sizeof(yes)) < 0)
    {
       perror("Reusing ADDR failed");
       return 1;
    }

        // set up destination address
    //
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY); // differs from sender
    addr.sin_port = htons(port);

    // bind to receive address
    //
    if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) 
    {
        perror("bind");
        return 1;
    }

    // use setsockopt() to request that the kernel join a multicast group
    //
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(group);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mreq, sizeof(mreq)) < 0)
    {
        perror("setsockopt");
        return 1;
    }

    // now just enter a read-print loop
    //
    while (1) 
    {
        char msgbuf[MSGBUFSIZE];
        const int addrlen = sizeof(addr);
        const int nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *) &addr, &addrlen);

        if (nbytes < 0) 
        {
            perror("recvfrom");
            return 1;
        }
        msgbuf[nbytes] = '\0';
        puts(msgbuf);
     }

    return 0;
}

Ответы [ 2 ]

2 голосов
/ 25 октября 2019

В отличие от TCP, который объединяет пакеты в поток, UDP учитывает границы пакетов, поэтому recvfrom получает только один пакет за раз.

Таким образом, MSGBUFSIZE должен быть размером не более одного пакета. Если вы не используете гигантские пакеты, это будет 1500, в противном случае это будет 9000.

1 голос
/ 25 октября 2019

, как отмечает @Ingo, в этом коде вы должны использовать:

    char msgbuf[MSGBUFSIZE + 1];

+ 1, потому что recvfrom может записать до MSGBUFSIZE байтов в массив, а затем вы пишетееще один байт NUL в конце.

, если выбрать значение для MSGBUFSIZE, которое будет зависеть от спецификации протокола. учитывая, что большинству физических сетей будет трудно отправлять более 1500 байтов без фрагментации, что-то вроде 2048 может быть разумным значением. Вы также можете проверить nbytes == MSGBUFSIZE (возможно, также используя MSG_TRUNC) и сообщить о «усеченном пакете» предупреждении, но это в основном не произойдет для пакетов, маршрутизируемых через общедоступный Интернет

в ответ на:

мне нужно хранить несколько пакетов, пока я обрабатываю первый?

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

...