【问题标题】:sendto() to non existing socketsendto() 到不存在的套接字
【发布时间】:2013-12-20 22:36:03
【问题描述】:

我正在编写一个通过套接字(从客户端到服务器)发送数据的应用程序。我观察到非常奇怪的行为:当我杀死服务器时,首先发送,然后杀死就像服务器存在一样。下一个返回 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)

问候 J

【问题讨论】:

  • 套接字是什么协议? UDP? TCP?
  • 对不起,忘了说:我正在使用 TCP 套接字
  • 服务器应用程序本身是否打开了 TCP 连接?或者它是继承它还是从另一个进程获取它?任何其他进程都可以拥有该套接字的副本吗?服务器是否通过连接调用fork 而没有在孩子中关闭它? (对此可以有很多解释。这并不是特别不寻常。)

标签: c sockets


【解决方案1】:

TCP 不保证在您尝试在其上发送一些数据之前会检测到断开的连接。一旦您尝试这样做,您可能会收到来自网络的错误,或者发送操作可能会超时。由于应用级 TCP 仅在没有足够的可用缓冲区空间时才进行写入阻塞,因此通常会在可以报告这些错误的下一个操作中报告错误。

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2015-07-27
      • 2014-05-23
      • 1970-01-01
      • 2021-01-24
      • 2012-06-15
      • 2011-02-09
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多