关闭的套接字上第二次发送时出现“Broken pipe”错误

7
我正在通过TCP套接字测试客户端和服务器的通信。我使用C编写了服务器并在Linux机器上运行,并使用nc作为测试客户端。
在与客户端进行初始消息交换后,服务器会定期向客户端发送一些消息,而不会收到任何响应。
如果我终止客户端,我希望服务器的第一个send()将失败并显示EPIPE错误,但是这只会在客户端离开后的第二个send()中出现!在我杀死客户端后,第一个send()能够成功地将1100个字节发送到(我想关闭的)套接字。随后的send()操作以预期的EPIPE结束。
有人可以解释这种行为吗? 这是因为我写入了TCP/IP堆栈,所以由堆栈决定何时传递吗? 如果是这样,如何检查连接状态?确保对等方仍然存在。
1个回答

4

普通的TCP连接是四次握手。

http://en.wikipedia.org/wiki/Transmission_Control_Protocol

当您关闭客户端时,FIN段从客户端发送到服务器,服务器协议栈发送ACK。如果服务器试图读取数据,读取调用将返回值0,因此您的服务器程序可以理解对等方已关闭,并通常在此之后关闭连接套接字。这将允许从服务器端发送FIN并在收到客户端侧的最后一个ACK后完成正常的4次握手。(请阅读http://www.faqs.org/faqs/unix-faq/socket/中的Q 2.1)但是,在这里,您正在从服务器写入数据,因此仅在发送数据后,服务器才会从客户端获得RESET。因此,您在第二个发送上执行第一次发送操作后会出现错误。

因此,请尝试通过设置延迟选项和超时时间为0,从客户端突然关闭连接,而不是进行4次握手,这样您可以在服务器端的第一次发送调用时获得一个错误(可能与EPIPE不同)。 (这不是推荐的做法,仅适用于您在这种特殊情况下的理解)

Try the following option of nc, nc -L 0 to set the linger option and timeout to 0

我没有尝试过nc的这个选项,请查看此链接http://docs.oracle.com/cd/E23824_01/html/821-1461/nc-1.html以获取详细信息。

以下是来自上述网站的nc示例:

Connect to TCP port, send some data and terminate the connection with 
TCP RST segment 
(instead of classic TCP closing handshake) by setting the linger option and 
timeout to 0:

$ echo "foo" | nc -L 0 host.example.com 22

感谢您的回答,详细而清晰。不幸的是,我无法测试您建议的“nc”选项,因为我的Linux机器上的命令似乎不支持它。顺便说一下,您给我的文档指引和解释非常清晰和有用。谢谢! - Igor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接