Будет ли UDP sendto в linux возвращать ENOBUFS? - PullRequest
2 голосов
/ 09 марта 2020

Я проследил исходный код linux по всему процессу отправки udp.

Я думаю, что возвращаемое значение sendto () возвращается rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK;. Когда qdis c заполнен, он отбрасывает пакет и возвращает NET_XMIT_DROP, затем значение будет преобразовано в ENOBUFS.

Ниже приведен мой вопрос. Я написал клиентское приложение udp. Он отправил пакет udp, и я позволил ему непрерывно получать кадр паузы PF C, который вызывал переполнение буфера пакетов NI C, txring драйвера и qdis c. Однако

  • sendto () блокируются в режиме блокировки и получают errno EAGAIN в неблокирующем режиме, что означает, что буфер сокета отправки UDP заполнен. Тем не менее, полный qdis c просто отбрасывает пакет, когда пакет ставится в очередь, почему буфер отправки UDP будет заполнен?
  • Нет ENOBUFS вернулось, даже если я установил длину qdis c меньше на ifconfig txqueuelen 10. Программа выполнила setsockopt(sockfd, SOL_IP, IP_RECVERR,(char*)&val, sizeof(val));, но не вернула ошибку. Поскольку есть несколько примеров использования IP_RECVERR, если в моем коде есть неправильное использование, пожалуйста, сообщите мне. Большое спасибо!
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <time.h>
#include <linux/errqueue.h>


#define UDP_TEST_PORT       5000
#define UDP_SERVER_IP       "10.0.10.34"

int ip_control_msg( struct cmsghdr *msg )
{
    int ret = 0;
    switch( msg->cmsg_type ){
    case IP_RECVERR:
        {
            struct sock_extended_err *exterr;
            exterr = (struct sock_extended_err *)(CMSG_DATA(msg));
            printf("ee_errno: %u\n", exterr->ee_errno );
            printf("ee_origin: %u\n", exterr->ee_origin );
            printf("ee_type: %u\n", exterr->ee_type );
            printf("ee_code: %u\n", exterr->ee_code );
            printf("ee_pad: %u\n", exterr->ee_pad );
            printf("ee_info: %u\n", exterr->ee_info );
            printf("ee_data: %u\n", exterr->ee_data );
        }
        ret = -1;
        break;
    default:
        break;
    }
    return ret;
}

int control_msg( struct msghdr *msg )
{
    int ret = 0;
    struct cmsghdr *control_msg = CMSG_FIRSTHDR( msg );
    while( control_msg != NULL ){
        switch( control_msg->cmsg_level ){
        case SOL_IP:
            ret = ip_control_msg( control_msg );
            break;
        default:
            break;
        }
        control_msg = CMSG_NXTHDR( msg, control_msg );
    }
    return ret;
}

int main(int argC, char* arg[])
{
    struct sockaddr_in addr;
    int sockfd, len = 0;    
    int addr_len = sizeof(struct sockaddr_in);      
    char buffer[4096];

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket");
        exit(1);
    }

    fcntl(sockfd,F_SETFL,O_NONBLOCK);

    int val = 1;
    setsockopt(sockfd, SOL_IP, IP_RECVERR,(char*)&val, sizeof(val));

    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(UDP_TEST_PORT);
    addr.sin_addr.s_addr = inet_addr(UDP_SERVER_IP);

    int rtn = 0;
    while(1) {
        bzero(buffer, sizeof(buffer));
        sprintf(buffer,"%d",cnt);
        rtn = sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&addr, addr_len);
        if(rtn<0){
           printf("%d\n",errno);
        }

        char buf[1024];
        char control_buf[1024];
        struct msghdr msg;
        struct iovec iov = { buf, 1024 };
        memset( &msg, 0, sizeof(msg) );
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = &control_buf;
        msg.msg_controllen = 1024;

        int bread = recvmsg( sockfd, &msg, MSG_ERRQUEUE );
        if( bread == -1 ){
            continue;
        }
        if( control_msg( &msg ) >= 0 )
            printf("successed!\n");
        else
            printf("failed!\n");
    }

    return 0;
}

1 Ответ

0 голосов
/ 10 марта 2020

Да, это может и не может быть ничего плохого в вашем коде, но вы все равно можете получить ENOBUFS. Потому что система может быть перегружена другими процессами. Проверьте это: https://www.unix.com/programming/237027-how-avoid-no-buffer-space-available-c-socket.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...