我有一个TCP服务器应用程序,偶尔需要通过关闭它们然后稍后打开它们来重新配置绑定端口。
应用程序还需要执行与之通信的外部二进制文件。目前使用popen()调用完成此操作。外部二进制运行时间可以跨越需要重新配置网络端口的时间段。
问题是,当主应用程序关闭一个端口时,它会由“分叉”接收。 popen为了运行二进制文件而创建的进程。
这是有道理的(它在What happens when a tcp server binds and forks before doing an accept ? Which process would handle the client requests?讨论过),但不可取,因为主应用程序无法重新打开端口。
是否可以使用popen(3)中可用的FD_CLOEXEC O_CLOEXEC?应用程序需要popen(3)提供的管道作为stdin到执行的二进制文件,当CLOEXEC关闭其他文件时,文件句柄保持打开状态。
是否有更好的方法来运行二进制文件,这会导致分叉进程无法保持关闭端口?
还有另一个可能相关的问题答案 0 :(得分:5)
不,你不能启动另一个程序,并且在没有fork(2)后跟一些execve(2)代码(popen
,posix_spawn
和{{1 }} 是做)。您最好避免system
或popen
并自己明确编码system
+ pipe
+ fork
(因为你知道吗应该保留哪些文件描述符以及close(2)哪些文件描述符通常在execve
之后和子进程中fork
之前...),请参阅{{3 }}
(除<{1}}以外的每个流程和程序以及一些热插拔内容都以execve
+ /sbin/init
开头;您的shell是对于大多数命令不断使用fork
+ execve
,除了fork
之类的内置命令
阅读一些好的书,例如 Advanced Linux Programming 在线免费提供的书籍clone(2)。另见here。使用(至少用于调试和理解事物)syscalls(2)和调试器(execve
)。研究strace(1) libc(free software或GNU libc)中cd
和gdb
的源代码,以及shell的源代码。
您可以通过棘手的序列musl-libc(以及相关的popen
)调用几乎模仿execve(2),但不完全(尤其是近距离执行等...)。您可能还需要调用过时的mmap(2)(或编写等效的汇编代码)。
您可以考虑与system
&amp;上的类似shell的类似服务器的程序进行通信。 munmap
(例如,请参阅我的setcontext(3)和灵感)。也许你会发现execicar.c很有用。
更好的选择可能是在您的应用中嵌入一些解释器(如daemon(3)或lua)和/或guile部分dlopen(3)。缺点是错误(在解释的脚本或插件中)会影响整个服务器。
答案 1 :(得分:0)
你绝对可以使用close-on-exec标志来避免新启动的进程继承打开的文件或套接字(并且没有其他方式我知道)。如果您使用open(2)
打开文件,则可以通过将O_CLOEXEC
添加到文件创建标志来设置此时的标志。如果文件已经打开,您可以使用fcntl()
进行设置(如果您使用fopen(3)
打开文件,则可以通过fileno(3)
获取此文件所需的文件描述符。对于套接字,您还可以通过设置socket(2)
在使用SOCK_CLOEXEC
打开时设置标记。没有设置此标记的文件将由您的程序生成的进程继承,无论是直接通过fork + exec
还是该组合的任何其他“伪装”,例如system(3)
或popen(3)
。< / p>