使用阻塞I / O通过套接字读取所有可用字节

时间:2014-02-25 09:42:05

标签: c linux sockets bsd

使用read(2)从套接字读取并阻止I / O时,何时知道另一方(客户端)没有更多数据要发送? (通过“不再发送数据”我的意思是,作为一个例子,客户端正在等待响应)。起初,我认为countread)返回的字节少于read(fd, *buf, count)时就达到了这一点。

但是,如果客户端发送碎片数据怎么办?在read返回0之前阅读将是一个解决方案,但据我所知0仅在客户端关闭连接时返回 - 否则,read将阻止直到连接已关闭。我想过使用非阻塞I / O和select(2)的超时,但这对我来说似乎不是一个整洁的解决方案。

有没有已知的最佳做法?

3 个答案:

答案 0 :(得分:1)

TCP是字节流协议,而不是消息协议。如果你想要消息,你必须自己实现它们,例如使用长度字前缀,行,XML等。您可以使用ioctl()的FIONREAD选项进行猜测,但猜测就是它的全部,因为您无法知道客户端是否在传输过程中暂停了消息,或者网络是否由于某种原因这样做了。

答案 1 :(得分:1)

协议需要让您了解客户端何时完成发送消息。

常见的方法是在每个消息之前发送每条消息的长度,或者在每条消息之后发送一个特殊的终止符(类似于C中字符串末尾的NUL字符)。

答案 2 :(得分:1)

“另一方没有更多数据要发送”的概念,没有超时或传输数据中的某些语义,这是毫无意义的。通常,客户端/服务器上的代码将能够比网络传输数据更快地处理数据。因此,当您尝试read()时,如果接收缓冲区中没有数据,这只意味着网络尚未 传输所有内容,但您无法判断下一个是否数据包将在一毫秒,一秒或一天内到达。您可能会认为第一种情况是“需要发送更多数据”,第三种情况是“不再发送数据”,第二种情况取决于您的应用程序。

如果对方没有关闭连接,您可能不知道它何时准备发送下一个数据包。

因此,除非您具有关于客户端发送内容的特定语义和知识,否则使用select()和非阻塞I / O是您可以做的最佳选择。

在特定情况下,可能还有其他方式 - 例如,如果您知道客户端将发送XML标记,某些数据和结束标记,则每 n 秒。在这种情况下,您可以在收到最后一个数据包后开始读取 n 秒,然后继续阅读,直到收到结束标记。但正如我所说,这不是一般方法,因为它需要通道上的语义。