我已经在整个udp发送过程中跟踪了linux源代码。

我认为sendto()的返回值是由rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK;返回的。当qdisc已满时,它将丢弃数据包并返回NET_XMIT_DROP,然后将该值转换为ENOBUFS

以下是我的问题。
我写了一个udp客户端应用程序。它发出了udp数据包,让它连续接收PFC暂停帧,这导致NIC的数据包缓冲区,驱动程序的txring和qdisc变满。然而,

  • sendto()在阻塞模式下被阻塞,而在非阻塞模式下得到errno EAGAIN,这意味着UDP发送套接字缓冲区已满。但是,完整的qdisc只是在数据包入队时才丢弃该数据包,为什么UDP发送缓冲区会变满?
  • 即使我通过ENOBUFS将qdisc的长度设置得更短,也没有返回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;
    }
    
    

    最佳答案

    是的,可以,您的代码可能没有任何问题,但是您仍然可以获得ENOBUFS。因为系统可能会被其他进程重载。看看这个:https://www.unix.com/programming/237027-how-avoid-no-buffer-space-available-c-socket.html

    关于c++ - Linux中的UDP sendto是否会返回ENOBUFS?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60601055/

    10-16 03:34