我知道fork和exec系列在执行后会保留文件描述符。这种行为对我的需求是可取的。同样来自exec手册:
exec()函数系列取代了当前的过程映像 使用新的过程映像。
所以,如果我做对了,在处理分支然后执行后,程序需要额外的方法来了解哪些fds是打开的。
我所寻求的是将新的过程中使用的fds(以及需要关闭的fds)传递给新过程的简单方法。
作为旁注。在Windows中,您只能看到进程正在使用的列表fds。你需要达到低水平才能做到这一点。
答案 0 :(得分:2)
没有系统调用只提供打开文件描述符列表。但是,您正在解决的更大问题可以通过几种不同的方式解决。最典型的两种方式是:
如果孩子只处理一个客户端,那么只需从stdin(fd 0)读取并写入其stdout(fd 1);在分叉之后但在执行之前,使用dup2
将相应的文件描述符重新分配给数字0和1,单独保留fd 2(stderr),然后关闭所有其他文件描述符(或者使用O_CLOEXEC
/ {{ 1}}提前,所以你不必这样做)。 一些 Unix有一个方便的函数叫FD_CLOEXEC
,它关闭所有数据值大于或等于其参数的文件描述符,但是其他Unix拒绝采用它,原因我完全考虑伪造的。
如果孩子正在与一个文件描述符中包含的套接字或其他全双工通信通道进行通信,则仍应将其指定为两者 fds 0和1,因为这样{{{ 1}}和closefrom
FILE对象可以正常使用(无论如何都需要使用stdin
,stdout
等),并且因为许多库感到困惑fds 0,1和2中的任何一个都没有打开。
此策略以最小的工作量提供了良好的并行度,并允许子程序与recvfrom
和类似的多路复用器一起使用。
如果孩子需要处理多个客户端,请不将任何客户端分配为fds 0或1;而是将逗号分隔的客户端套接字列表作为命令行参数进行处理。孩子应该只关注那些文件描述符,并忽略所有其他文件描述符,即使它们是开放的。 (你应该尽力在分叉之后但在执行之前关闭所有不相关的fds。)
为孩子中的多个客户端多路复用I / O需要更多的编程;如果您需要这条路线,我强烈建议您使用某人已为您编写的异步I / O库,例如shutdown
或inetd
。
在你确实需要知道哪些fds是开放的情况下,你的父母没有给你任何线索的情况下,你有一个糟糕且不可移植的选项,以及一个可怕但便携的选项。
错误且不可移植的选项是打开并扫描目录libevent
。 如果此目录存在,则其条目对应于进程中的打开文件描述符,其名称是十进制的描述符编号。这是一个糟糕的选择,因为你必须循环调用libuv
并注意避免fd支持你正在使用的/proc/self/fd
句柄,并且它是不可移植的,因为据我所知,只有 Linux实现了这个特殊的目录,即使在那里它也可能无法使用。
可怕但可移植的选项是用readdir
查询最大文件描述符号,然后从0循环到调用DIR
的那个号码,如果fd打开,它将返回一个非负号码,如果它已关闭,则为负数(并将errno设置为EBADF)。这可以在任何地方使用,但它可能非常慢,特别是如果最大文件描述符数量很大。