2011-06-24 21 views
1

假设客户端发送了100个字节的数据,但不知何故服务器只收到了90个字节。我如何处理这种情况?如果服务器在while循环内部调用“read”函数来检查接收到的总数据,那么服务器将永远等待包的最后10个字节。使用epoll处理短读取()

此外,可能发生客户端在数据传输中断。在这种情况下,服务器也将永远等待,直到它收到所有不会到达的数据。

我正在使用tcp,但在现实世界的网络环境中,可能会发生这种情况。在此先感谢...

回答

1

您不会在循环中调用read()函数,直到您接收到所需的字节数为止。相反,您将套接字设置为非阻塞,并在循环中调用read()函数,直到它返回0(表示数据流结束)或错误。

在正常情况下,循环将终止read()返回-1,其中errno设置为EAGAIN。这表示连接尚未关闭,但当前没有更多数据可用。此时,如果客户端还没有足够的数据,则只需保存您以后使用的数据,然后返回主循环epoll()

如果当其余的数据到达时,套接字将被返回为epoll()可读,您将read()剩余的数据,取回保存的数据并处理全部数据。

这意味着在每个套接字数据结构中需要空间来存储只读但尚未处理的数据。

1

您必须仔细检查返回值read。它可以返回任何三个东西:

一个正数,表示读取了一些字节。

零,表示另一端已正常关闭连接。

-1,表示发生错误。 (如果套接字是非阻塞的,那么错误EAGAIN或EWOULDBLOCK意味着连接仍然打开,但目前没有数据为您准备好,因此您需要等到epoll表示有更多数据给您。)

如果你的代码没有检查这三件事中的每一件,并以不同的方式处理它们,那么它几乎肯定会被破坏。如果客户端发送90个字节,然后关闭或粗暴地断开连接(因为read()将为这些情况返回0或-1),它们涵盖了所有您询问的情况。

如果您担心客户端可能发送90个字节,然后再也不发送任何消息,也不会关闭连接,那么您必须实现自己的超时。为此,最好的办法是使用非阻塞套接字并在select()/ poll()/ epoll()方法上设置超时时间,如果连接闲置时间过长,则将该连接抛开。

0

TCP连接是基于数据包网络顶层的双向流。只读取对方发送的部分内容是很平常的事情。你必须循环阅读,追加,直到你有一个完整的消息。为此,您需要使用TCP(FTP,HTTP,SMTP等)上使用的应用程序级协议(消息的类型,结构和语义)。

要回答问题的具体第二部分 - 将EPOLLRDHUP添加到epoll(7)事件组中,以在连接丢失时得到通知。

0

除了caf所说的之外,我建议只订阅EPOLLRDHUP,因为这是确定连接是否关闭的唯一安全方法(read()== 0不可靠,因为caf也提到了这一点,在发生错误的情况下可能是真的)。 EPOLLERR是订阅时总是,即使您没有特别要求。正确的行为是在EPOLLRDHUP情况下使用close()关闭连接,甚至在设置EPOLLERR时也可能会关闭连接。

欲了解更多信息,我在这里给出了类似的答案:epoll_wait() receives socket closed twice (read()/recv() returns 0)