我正在实现一个TCP / IP服务器应用程序,该应用程序在边缘触发模式下使用epoll并执行非阻塞套接字操作。客户端正在使用没有epoll的简单阻塞操作。
我不知道如何在服务器端实现“原子读取”。要解释我对“原子读取”的含义,请参阅此示例并使用简单的阻塞操作:
但是对于epoll +非阻塞操作,可能会发生这种情况:
在这种情况下,读取不是“原子的”。不保证当使用单个写操作写入数据时,读取将以整体形式返回整个数据。
是否可以知道数据何时是部分的?我知道一个解决方案是始终将数据大小附加到开头,或者另一个解决方案是始终关闭并重新打开连接,但我不想这样做:因为我认为内核必须知道不是完整的“包”(该单位如何称为BTW?)到了,因为它保证了阻塞操作的原子性。
非常感谢!
答案 0 :(得分:1)
TCP是基于流的,而不是面向消息的。即使在阻塞套接字的情况下,也无法保证应用程序发送的内容将一次性发送到线路上。 TCP将决定自己的方向。
因此,应用程序要做" atomic"读它的愿望。例如:
应用程序协议应该规定消息应该以长度字节为前缀。长度字节通知对等体感兴趣的应用程序数据的大小。当然,应用程序应该知道两个字节长度指示符何时开始。
[2字节msg长度] [感兴趣的数据字节]
根据此信息,正在阅读的应用程序应采取措施。它应该轮询套接字,直到它接收到msg长度字节所指示的所有字节。然后才处理数据。
如果你需要" atomic"读取而非部分读取您可以在recv
中使用MSG_PEEK标志。这不应该从套接字缓冲区中删除数据。应用程序查看套接字,根据返回值查看所需的数据是否在套接字缓冲区中。
ret = recv(sd, buf, MAX_CALL_DATA_SIZE, MSG_PEEK);