我知道当对等端的套接字关闭时,会引发损坏的管道错误。
但是,在我的测试中,我注意到当对等端关闭时,在这一端立即“发送”调用并不总是导致管道损坏错误。
例如:
在对等端关闭套接字后(我通过调用 close 尝试干净关闭,也通过杀死对等端尝试异常关闭),如果我尝试发送 40 个字节,那么我不会得到一个损坏的管道,但是,如果我尝试发送 40000 字节然后它立即给出损坏的管道错误。
究竟是什么原因导致管道破裂,它的行为可以预测吗?
我知道当对等端的套接字关闭时,会引发损坏的管道错误。
但是,在我的测试中,我注意到当对等端关闭时,在这一端立即“发送”调用并不总是导致管道损坏错误。
例如:
在对等端关闭套接字后(我通过调用 close 尝试干净关闭,也通过杀死对等端尝试异常关闭),如果我尝试发送 40 个字节,那么我不会得到一个损坏的管道,但是,如果我尝试发送 40000 字节然后它立即给出损坏的管道错误。
究竟是什么原因导致管道破裂,它的行为可以预测吗?
观察网络关闭可能需要一些时间 - 总时间通常是在关闭之后大约 2 分钟(是的,几分钟!),然后发往该端口的数据包都被假定为死亡。在某个时间点检测到错误情况。只需少量写入,您就处于系统的 MTU 内部,因此消息将排队等待发送。有了大写,您就比 MTU 更大,系统可以更快地发现问题。如果您忽略 SIGPIPE 信号,则函数将在损坏的管道上返回 EPIPE 错误 - 在某个时候检测到连接的损坏。
套接字的当前状态由“保持活动”活动确定。在您的情况下,当您发出send
调用时,keep-alive
活动可能会告诉套接字处于活动状态,因此send
调用会将所需的数据(40 字节)写入缓冲区并返回而不会给出任何错误。
当您发送更大的块时,发送调用进入阻塞状态。
发送手册页也证实了这一点:
当消息不适合套接字的发送缓冲区时,send() 通常会阻塞,除非套接字已被置于非阻塞 I/O 模式。在非阻塞模式下,在这种情况下它会返回 EAGAIN
因此,在阻塞空闲可用缓冲区时,如果(通过保持活动机制)通知调用者另一端不再存在,则发送调用将失败。
使用上述信息很难预测确切的情况,但我相信,这应该是您遇到问题的原因。
也许 40 字节适合管道缓冲区,而 40000 字节不适合?
编辑:
当您尝试写入已关闭的管道时,发送进程会发送一个 SIGPIPE 信号。我不确切知道何时发送信号,或者管道缓冲区对此有何影响。您可以通过使用 sigaction 调用捕获信号来恢复。
当对等体关闭时,您只是不知道它是停止发送还是停止发送和接收。因为TCP允许这样做,顺便说一句,您应该知道关闭和关闭之间的区别。如果对端都停止发送和接收,首先发送一些字节,它会成功。但是对等内核会向您发送 RST。因此,随后您发送一些字节,您的内核将向您发送 SIGPIPE 信号,如果您捕获或忽略此信号,当您的发送返回时,您只会收到 Broken pipe 错误,或者如果您没有,您的程序的默认行为正在崩溃.