这更多是一种观察,也是对处理这种情况的最佳方法的建议。
我有两个线程,一个只是泵入数据,另一个则接收数据并在发送另一个套接字之前做了很多工作。两个线程都通过域套接字连接。此处使用的协议(protocol)是UDP。我不想使用TCP,因为它是基于流的,这意味着如果队列中的空间很小,则将数据拆分并发送。这很不好,因为Iam发送了不应拆分的数据。因此,我使用了DGRAM。有趣的是,当发送线程通过泵送大量数据而使recv线程不堪重负时,在某些时候,域套接字缓冲区被填满,并且sendto()返回ENOBUFS。我认为如果发生这种情况,sendto()将阻塞直到缓冲区可用为止。这将是我想要的行为。但是,事实似乎并非如此。我以一种相当怪异的方式解决了这个问题。
如果得到ENOBUFS,则执行sched_yield();。因为OSX中没有pthread_yield()。之后,我尝试重新发送。如果失败,我将继续这样做直到采取措施。这很不好,因为Iam浪费了CPU周期,只是做些无用的事情。如果sendto()被阻止,我将很高兴。
我试图使用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/