这更多是一种观察,也是对处理这种情况的最佳方法的建议。

我有两个线程,一个只是泵入数据,另一个则接收数据并在发送另一个套接字之前做了很多工作。两个线程都通过域套接字连接。此处使用的协议(protocol)是UDP。我不想使用TCP,因为它是基于流的,这意味着如果队列中的空间很小,则将数据拆分并发送。这很不好,因为Iam发送了不应拆分的数据。因此,我使用了DGRAM。有趣的是,当发送线程通过泵送大量数据而使recv线程不堪重负时,在某些时候,域套接字缓冲区被填满,并且sendto()返回ENOBUFS。我认为如果发生这种情况,sendto()将阻塞直到缓冲区可用为止。这将是我想要的行为。但是,事实似乎并非如此。我以一种相当怪异的方式解决了这个问题。

  • CPU产量方法
    如果得到ENOBUFS,则执行sched_yield();。因为OSX中没有pthread_yield()。之后,我尝试重新发送。如果失败,我将继续这样做直到采取措施。这很不好,因为Iam浪费了CPU周期,只是做些无用的事情。如果sendto()被阻止,我将很高兴。
  • sleep 方法
    我试图使用sleep(1)而不是sched_yield()解决相同的问题,但这没有用作为sleep()会使我的进程进入休眠状态,而不仅仅是发送线程。

  • 他们两个似乎都不适合我,而Iam的选择也用光了。有人可以建议什么是解决此问题的最佳方法吗? Iam是否知道一些巧妙的技巧可以减少不必要的cpu​​周期?顺便说一句,基于http://lists.freebsd.org/pipermail/freebsd-hackers/2004-January/005385.html的讨论,手册页上关于sendto()的说法是错误的

    内核中的Upd代码:
    The udp_output function in /sys/netinet/udp_usrreq.c, seems clear:
    
             /*
              * Calculate data length and get a mbuf
              * for UDP and IP headers.
              */
             M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
             if (m == 0) {
                     error = ENOBUFS;
                     if (addr)
                             splx(s);
                     goto release;
             }
    

    最佳答案

    我不确定为什么sendto()不会为您阻塞...但是您可以在每次调用sendto()之前尝试调用此函数:

    #include <stdio.h>
    #include <sys/select.h>
    
    // Won't return until there is space available on the socket for writing
    void WaitUntilSocketIsReadyForWrite(int socketFD)
    {
       fd_set writeSet;
       FD_ZERO(&writeSet);
       FD_SET(socketFD, &writeSet);
       if (select(socketFD+1, NULL, &writeSet, NULL, NULL) < 0) perror("select");
    }
    

    顺便说一句,您要发送的数据包有多大?

    关于macos - sendto()dgram在OSX上不会阻止ENOBUFS,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16555101/

    10-12 17:12