2013-04-29 108 views
0

我想在特定的时间间隔后写入一些数据在套接字。我有两个线程,一个线程维护TCP连接,另一个线程生成数据。写入到客户端时返回EWOULDBLOCK当服务器很慢

生成therad的数据生成数据,并将其写入共享内存。服务器线程从共享内存读取数据,并将其发送到客户端。

但是,当数据生成线程变慢时,当涉及大量计算时,服务器线程在尝试写入客户端时会收到EWOULDBLOCK错误。但令人惊讶的是,从客户端来看,没有这样的错误。

如果我没有错,当服务器速度比客户端快,并且在再次写入套接字缓冲区之前没有完全读取套接字缓冲区时,会返回EWOULDBLOCK错误。但是,这里的情况完全相反。

难道是因为服务器Therad一直处于睡眠状态直到数据生成线程完成(数据线程具有更高的优先级)。

有人可以解释可能发生的事情吗?

回答

6

当您使用非阻塞套接字并且内核的传出数据缓冲区中没有足够的空间来容纳您要发送的任何数据时,会返回EWOULDBLOCK。如果客户端读取速度太慢,可能会发生这种情况,但如果服务器尝试一次发送大量数据,也可能发生(即使使用快速客户端)。例如,如果你的计算线程花费很长的时间来计算的数据,然后在突然经过一次30万个字节的数据的计算结束,你的服务器线程可能会做这样的事情:

  1. 看到一些数据在共享内存区域可用,开始发送它的时间!
  2. 用len = 300000调用send()。 send()会吸收尽可能多的数据,因为它可以放入内核的传出套接字数据缓冲区(例如131,072字节),并返回131072来指示它完成了什么。
  3. 现在你的服务器线程发现它仍然有168928字节的数据要发送,所以它再次调用len = 168928的send()。此时,内核的outgoing-socket-data-buffer仍然是满的(因为还没有机会发送任何数据包),所以send()返回EWOULDBLOCK。

一般来说,只要你使用非阻塞套接字,EWOULDBLOCK就是你的代码需要处理的东西。我通常处理它的方式是:

  1. 等在内的select()(或poll()或等),直至插槽返回准备就绪写
  2. 当选择()/调查()表示套接字准备好写入,在套接字上调用send()直到你发送了所有可用的数据,或者直到send()返回EWOULDBLOCK(以先到者为准)。
  3. 如果您在步骤2中得到EWOULDBLOCK,转到1

这样,你发送线程会一直喂输出数据到内核尽可能快,但没有速度更快 - 即你不浪费任何CPU忙于循环,但您也不会浪费时间,将任何不必要的延迟插入进程。

+0

嗨杰里米,非常感谢..我会尝试读取共享内存中的数据量,看看是否真的是这个问题.. – Hariprasad 2013-04-29 15:54:50

+0

优秀的解释,非常感谢。 – 2017-06-15 03:57:50