2015-09-04 89 views
4

Linux/UNIX系统上常见的服务器套接字模式是在套接字上侦听,接受连接,然后使用fork()来处理连接。在fork()后关闭监听套接字()

所以,看起来你在accept()fork()之后,一旦你进入了子进程,你就会继承父进程的监听文件描述符。我已经读过,在这一点上,您需要关闭子进程内的侦听套接字文件描述符。

我的问题是,为什么?这是否简单地减少了监听套接字的引用计数?还是这样,子进程本身不会被OS用作路由传入连接的候选者?如果是后者,我有点困惑,原因有两个:

(A)告诉操作系统某个进程是否可以接受某个文件描述符上的连接?这个过程叫做accept()是事实吗?或者这个过程叫做listen()? (B)如果这个过程叫做listen(),那么我们在这里没有竞争条件吗?如果这种情况发生什么:

  1. 父进程监听套接字S.
  2. 传入连接转到父进程。
  3. 父进程叉一个孩子,孩子有插座S
  4. 的副本之前孩子能够调用close(S),一个传入连接进入子进程。
  5. 子进程永远不会调用accept()(因为它不应该),所以进入的连接被丢弃

什么防止上述情况的发生?更一般地说,为什么一个子进程关闭监听套接字?

回答

6

Linux队列挂起挂起的连接。从父进程或子进程调用accept将轮询该队列。

不关闭子进程中的套接字是一个资源泄漏,但没有多少其他。父节点仍将获取所有传入的连接,因为它是唯一一个调用accept的连接,但是如果父节点退出,则该套接字仍然存在,因为它在子节点上处于打开状态,即使该子节点从未使用它。

0

子进程继承其父级的所有文件描述符。子进程应关闭所有侦听套接字以避免与其父进行冲突。

+0

这不回答这个问题。提问者想知道为什么有必要关闭所有文件描述符,以及如果不这样做会发生什么。 – dbush

2

传入的连接将被“传递”,任何进程正在呼叫accept()。在关闭文件描述符之前分叉之后,可以在两个进程中接受连接。

所以只要你永远不会接受子线程中的任何连接,并且父母继续接受连接,一切都会正常工作。

但是,如果您打算永远不接受您的子进程中的连接,为什么要在此过程中为套接字保留资源?

有趣的问题是如果两个进程在套接字上调用accept()会发生什么。目前我还找不到关于此的明确信息。我能找到的是,可以肯定的是,每个连接只能交付给其中一个流程。

+0

“*如果两个进程都在套接字上调用accept()会发生什么情况。*”两个进程之一都会以未指定的方式接受()'连接。 – alk

+0

“* unspecified manner。*”在我以前的评论中会说它是“* unspecified *”,哪个进程会得到accept()连接。 – alk

0

除非调用accept(),否则子进程将不会在套接字上侦听,在这种情况下,传入连接可以转到任一进程。

+0

至少在Linux中,并不是真的有'listen()'这个操作系统的进程。 – alk