如果没有结束调用close()或崩溃,会导致自发EPIPE错误的原因是什么?

时间:2010-02-10 10:13:39

标签: unix sockets ipc posix

我有一个由两个进程组成的应用程序(让我们称之为A和B),通过Unix域套接字相互连接。大部分时间它工作正常,但有些用户报告以下行为:

  1. A向B发送请求。这有效。 A现在开始阅读B的回复。
  2. B向A发送回复。相应的write()调用返回EPIPE错误,结果B关闭()套接字。但是,A确实关闭()套接字,也没有崩溃。
  3. A的read()调用返回0,表示文件结束。 A认为B过早地关闭了连接。
  4. 用户还报告了此行为的变体,例如:

    1. A向B发送请求。这部分工作,但在发送整个请求之前A的write()调用返回EPIPE,结果是一个close()套接字。但是B没有关闭()套接字,也没有崩溃。
    2. B读取部分请求然后突然获得EOF。
    3. 问题是我无法在本地重现此行为。我试过OS X和Linux。用户使用各种系统,主要是OS X和Linux。

      我已经尝试并考虑过的事情:

      • 双关闭()错误(在同一个文件描述符上调用close()两次):可能不会导致EBADF错误,但我还没有看到它们。
      • 增加最大文件描述符限制。一位用户报告说这对他有用,其余用户报告说没有。

      还有什么可能导致这样的行为?我肯定知道A和B都不会过早地关闭()套接字,并且我肯定地知道它们都没有崩溃,因为A和B都能够报告错误。好像内核突然决定出于某种原因从插座拔出插头。

3 个答案:

答案 0 :(得分:3)

也许你可以按照http://modperlbook.org/html/6-9-1-Detecting-Aborted-Connections.html

中的描述尝试strace

我认为您的问题与此处描述的问题有关:http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable

不幸的是,我自己有一个similar problem,但无法通过给定的建议来解决问题。但是,也许SO_LINGER对你有用。

答案 1 :(得分:2)

  • shutdown() 可能已经被召唤过了其中一个 套接字端点。

  • 如果任何一方可以分叉并执行a 孩子的过程,确保 FD_CLOEXEC (close-on-exec)标志设置在 套接字文件描述符,如果你没有 打算让它继承 儿童。否则孩子进程 可能(意外或其他方面) 操纵套接字连接。

答案 2 :(得分:0)

我还会检查中间没有偷偷摸摸的防火墙。路由上的中间转发节点可能会发送RST。追踪失败的最佳方法当然是the packet sniffer(或其GUI cousin。)