我有一个客户端-服务器应用程序,其中每一方都通过 TCP 套接字与另一方通信。
我正确建立了连接,然后在客户端将任何数据写入套接字之前使服务器崩溃。
我看到的是第一次write()
尝试(客户端)是成功的,它返回实际写入的字节数,而下面的返回(如我所料)-1
(接收 a SIGPIPE
)和errno=EPIPE
.
为什么第一个write()
成功,即使套接字已经关闭?
编辑
有时以下write()
也有一个正的返回值,好像一切顺利。
您对返回值的write()
含义感到困惑。这并不意味着“对等方获得了数据并确认了它”。相反,它的意思是,“我缓冲了这么多字节以发送给对等方,现在它们是我的责任,所以你可以忘记它们(而且我没有任何未决错误)”。
也就是说,如果 TCP 堆栈接受写入并返回n个字节,这并不意味着它们已经被写入,只是排队等待写入。在堆栈放弃并向您返回错误之前,可能需要一些时间,可能是在它开始发送网络流量后 30 秒。在那段时间里,您可以进行多次调用,这些调用write()
成功地将数据排队等待发送。(如果peer已经消失,写错误将在c.30s内返回,或者如果可以联系到peer并立即发送RST数据包以指示连接已死,则立即返回。)
这与 TCP/IP 的工作方式有关,可以粗略地描述为两个大部分独立的半连接。当您关闭服务器上的套接字时,客户端被告知它将不会从C<-S
半连接中接收更多数据,立即唤醒read()
,但与C->S
方向无关。它仅在尝试发送一些数据后才会收到重置连接的回复。我推荐TCP/IP 指南以获取更多详细信息。
有时你可以两次的原因write()
是你写得比往返时间快,并且可以write()
在回复第一个之前挤一秒钟。
我正在使用以下方法来检测断开连接的服务器状况:
在套接字上获得 select() 超时后(没有收到任何东西,但应该收到),'system("ping -c 1 -w 1 server");' 命令被激活。如果服务器启动并且只是滞后,ping 命令将在不到 0.1 秒内返回。否则(服务器宕机),ping 命令将在 1 秒后返回。