假设客户端发送了 100 个字节的数据,但不知何故服务器只收到了 90 个字节。我该如何处理这种情况?如果服务器在 while 循环中调用“读取”函数检查接收到的总数据,那么服务器将永远等待包最后 10 个字节。
此外,客户端可能会在数据传输过程中断开连接。在这种情况下,服务器也将永远等待,直到它接收到所有不会到达的数据。
我正在使用 tcp,但在现实世界的网络环境中,可能会发生这种情况。提前致谢...
假设客户端发送了 100 个字节的数据,但不知何故服务器只收到了 90 个字节。我该如何处理这种情况?如果服务器在 while 循环中调用“读取”函数检查接收到的总数据,那么服务器将永远等待包最后 10 个字节。
此外,客户端可能会在数据传输过程中断开连接。在这种情况下,服务器也将永远等待,直到它接收到所有不会到达的数据。
我正在使用 tcp,但在现实世界的网络环境中,可能会发生这种情况。提前致谢...
read()
在收到所需的字节数之前,不要在循环中调用该函数。相反,您将套接字设置为非阻塞并read()
在循环中调用该函数,直到它返回0
(指示流结束)或错误。
在正常情况下,循环将通过read()
返回 -1 来终止,并errno
设置为EAGAIN
。这表明连接尚未关闭,但当前没有更多可用数据。此时,如果您还没有来自客户端的足够数据,您只需保存您拥有的数据以备后用,然后返回主epoll()
循环。
如果当剩余数据到达时,套接字将被返回为可读的epoll()
,您将read()
接收剩余的数据,检索保存的数据并处理所有数据。
这意味着您需要每个套接字数据结构中的空间来存储已读取但尚未处理的数据。
您必须仔细检查 的返回值read
。它可以返回以下三项中的任何一项:
一个正数,表示读取了一些字节。
零,表示另一端已经优雅地关闭了连接。
-1,表示发生错误。(如果套接字是非阻塞的,则错误 EAGAIN 或 EWOULDBLOCK 表示连接仍处于打开状态,但现在没有数据可供您使用,因此您需要等到epoll
有更多数据可供您使用。)
如果您的代码没有检查这三件事中的每一个并以不同的方式处理它们,那么它几乎肯定会被破坏。
这些涵盖了您询问的所有情况,例如客户端发送 90 个字节然后关闭或粗鲁地断开连接(因为对于这些情况, read() 将返回 0 或 -1)。
如果您担心客户端可能会发送 90 个字节然后不再发送,并且永远不会关闭连接,那么您必须实现自己的超时。为此,您最好的选择是非阻塞套接字并在 select() / poll() / epoll() 上设置超时,如果连接空闲时间过长则放弃连接。
除了 caf 所说的,我建议只订阅 EPOLLRDHUP 因为这是确定连接是否关闭的唯一安全方法(read() == 0 不可靠,因为 caf 也提到了这一点,可能是真的发生错误时)。EPOLLERR总是被订阅的,即使你没有特别要求它。正确的行为是在 EPOLLRDHUP 的情况下使用 close() 关闭连接,甚至在设置了 EPOLLERR 时也是如此。
有关更多信息,我在这里给出了类似的答案:epoll_wait() 接收套接字关闭两次 (read()/recv() 返回 0)
TCP 连接是分层在基于数据包的网络之上的双向流。只读取对方发送的部分内容是很常见的。你必须循环阅读,追加直到你有完整的消息。为此,您需要在 TCP 之上使用的应用程序级协议 - 消息的类型、结构和语义(FTP、HTTP、SMTP 等都是此类协议)。
要回答问题的特定第二部分 - 添加EPOLLRDHUP
到epoll(7)
事件集以在连接断开时得到通知。