sendto()到非现有套接字

时间:2013-12-20 13:25:22

标签: c sockets

我正在编写一个通过套接字(从客户端到服务器)发送数据的应用程序。我观察到非常奇怪的行为:当我杀死服务器时,首先发送后杀死行为就像服务器存在一样。下一个返回EPIPE。你能解释一下为什么吗?

这是来自客户端应用程序的strace:

(server not killed)
...
sendto(5, "\0\1\0\0\0\0\0\0000\311\0\0\211A\264R\0\0\0\0\232\377\4\0\0\0\0\0\0\0\0\0"..., 51516, MSG_NOSIGNAL, NULL, 0) = 51516
....
(server killed)
****sendto(5, "\0\1\0\0\1\0\0\0000\311\0\0\272A\264R\0\0\0\0c%\0\0\0\0\0\0\0\0\0\0"..., 51516, MSG_NOSIGNAL, NULL, 0) = 51516,****
(next send after server is killed)
sendto(5, "\0\1\0\0\2\0\0\0000\311\0\0\375A\264R\0\0\0\0d\307\n\0\0\0\0\0\0\0\0\0"..., 51516, MSG_NOSIGNAL, NULL, 0) = -1 EPIPE (Broken pipe)

问候 Ĵ

2 个答案:

答案 0 :(得分:2)

TCP不保证在您尝试发送某些数据之前会检测到切断的连接。一旦尝试,您可能会从网络收到错误,或者发送操作可能会超时。由于应用程序级TCP写入仅在可用缓冲区空间不足时才会阻塞,因此通常会在下一个可报告这些错误的操作中报告错误。

虽然通常会立即检测到切断的连接,但并不总是如此,并且不能保证。确切的原因可能因我们不知道的很多因素而有所不同。 (服务器应用程序本身是否打开了TCP连接?或者它是继承它还是从另一个进程获取它?任何其他进程是否都有该套接字的副本?服务器是否通过连接调用fork而不是在子进程中关闭它?)

答案 1 :(得分:1)

在TCP中,连接的两个方向独立运行。当服务器关闭连接时,它会在服务器 - >客户端方向发送一条消息,表明它已完成传输;如果客户端执行read()recv(),则会在此时获得EOF。

但是,此消息没有说明客户端 - >服务器方向。 TCP没有为服务器提供任何方式告诉客户端它不愿意再读取任何数据。因此,客户端无法在尝试发送之前知道发送将失败。

当服务器从客户端收到新消息时,如果没有服务器进程仍在尝试从连接中读取,则服务器会向客户端发送RST消息。这是异步的 - 客户端上的sendto()调用已经返回(实际上,它会在将数据复制到内核缓冲区之后立即返回,然后才会将任何内容发送到网络)。当客户端TCP堆栈收到RST消息时,它会在套接字上设置error标志,并且 next 时间客户端尝试对其获取的套接字执行任何操作EPIPE错误。