【问题标题】:What happens if the server closes the socket first?如果服务器先关闭套接字会发生什么?
【发布时间】:2012-08-20 05:11:06
【问题描述】:

情况如下:我有两台机器,A 和 B。A 监听一个端口 p。 B 创建一个套接字 s1 并连接到 p。 A 接受套接字 s2 中的连接。目前,A 和 B 可以通过套接字相互通信。

但是,如果我杀死 A 中的程序,然后在一段时间后重新启动该程序,B 不知道,因为在此期间它没有向 A 发送任何数据。现在 B 开始通过 s1 向 A 写入数据。接下来会发生什么?为什么?

其实我发现write调用没有失败但是A还是没有得到数据。而且,如果我把s1放到epoll设备中,我发现epoll_wait在调用write之后返回的事件是EPOLLERR | EPOLLHUP。为什么?

不幸的是,在这种情况下,它似乎丢失了数据,因为 `write' 调用没有失败,但 A 无法获取数据。有什么解决办法吗?

【问题讨论】:

  • B 应该得到EPIPE 失败的write。你怎么知道write 没有失败?一些示例代码 + 输出会有所帮助。
  • 一般情况下,您不能依赖写入时没有错误来指示数据已传输。您需要在关闭时检查错误。写入磁盘和套接字都是如此。

标签: linux sockets unix network-programming


【解决方案1】:
  1. 当你杀死一个已建立套接字的程序时,它会将 RST 发送到所有其他端。所以 B 应该在 s1 上收到 RST,并且以后对 s1 的所有调用都将返回错误。但是有些防火墙可能会过滤掉RST包,你可以用tcpdump查看RST包。

  2. 如果 B 在 step1 中没有收到 RST 数据包,当它继续向 A 发送其他数据包(写入)时,A 将回复 RST 数据包,并且一旦 B 收到此消息,以后对 B 的所有调用都将返回错误RST。

  3. 如果B在step2中也没有收到RST包,经过一定时间(写超时),B会断开连接,以后对B的所有调用都会返回错误。

    李>

可以看到,write调用很少返回错误,发送包返回成功,不关心远端是否收到包。

在您的情况下,您不会在调用 epoll_wait 后立即获得 EPOLLHUP,而是在收到 RST 或写入超时后

【讨论】:

  • 谢谢,事实上B没有尝试从A接收任何数据包,因为它扮演了sending module的角色。在这种情况下,我不能依靠write来保证数据传输
【解决方案2】:

如果套接字的另一端已关闭,则它实际上是可读的,并且read(或recv)调用将返回零,表明另一端的套接字已正常关闭。

【讨论】:

  • 谢谢,我已经把这个socket放到epoll设备中,等待EPOLLIN。然后在服务器自行关闭后立即返回。
【解决方案3】:

您写入了断开连接的流(即使您的机器不知道它已断开连接。既然您说“接受连接”,我假设您正在两台机器之间建立 TCP 连接。)

如果您使用的是 UDP,则没有 Listen/Connect/Accept,数据将发送到在 addr/port 上侦听的任何内容。但你不是在谈论UDP。 [编辑以阐明结论:]您正在将数据写入死连接(并且在某些时候很明显连接已死,现在您已尝试使用它)。写入数据并不会告诉你对方是否收到数据,成功告诉你对方已经将要发送的数据排队。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    相关资源
    最近更新 更多