我可以在没有 fork 的情况下执行 shell 或系统调用吗?
Can I execute a shell or system call without a fork?
我有一个 TCP 服务器应用程序,它偶尔需要通过关闭它们然后在稍后打开它们来重新配置绑定端口。
应用程序还需要执行外部二进制文件并与之通信。目前这是使用 popen() 调用完成的。外部二进制运行时间可以跨越需要重新配置网络端口的时间段。
问题是,当主应用程序关闭一个端口时,它会被 popen 创建到 运行 二进制文件的 'forked' 进程占用。
这是有道理的(在 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) 提供的管道作为执行二进制文件的标准输入,当 CLOEXEC 关闭其他文件句柄时,该文件句柄是否保持打开状态。
有没有更好的方法来 运行 二进制文件,它不会导致分叉进程保持关闭的端口?
How to fork process without inheriting handles?
还有一个可能相关的问题
不,您不能在没有 fork(2) followed by some execve(2) code (which is what popen
, posix_spawn
, and system
are doing). You'll better avoid popen
or system
and code the pipe
+fork
+execve
explicitly yourself (since you know which file descriptors should be kept and which to close(2), generally after the fork
and before the execve
in the child process...), see 的情况下启动另一个程序并从中返回。
(每个进程和程序,除了/sbin/init
和一些热插拔的东西,都是从fork
+ [=17=开始的]; 而你的 shell 对大多数命令不断使用 fork
+ execve
,除了像 cd
)
这样的内置命令
fork(2) call could be implemented by clone(2).
阅读一些好书,例如 高级 Linux 编程 在线免费提供的书 here. See also syscalls(2). Use (at least for debugging and to understand things) strace(1) and your debugger (gdb
). Study the source code of popen
and of system
in your free software libc (GNU libc or musl-libc),以及 shell 的源代码.
您几乎可以模仿execve(2) by a tricky sequence of mmap(2) (and related munmap
) calls, but not quite (in particular w.r.t. close-on-exec etc...). You'll probably need also to call the obsolete setcontext(3)(或编写等效的汇编代码)。
您可以考虑与专门的 shell 类服务器程序进行通信,执行 fork
和 execve
(请参阅我的 execicar.c for example and inspiration). Maybe you'll find daemon(3) 有用。
更好的选择可能是嵌入一些解释器(如 lua or guile) in your application and/or to dlopen(3) some plugin。缺点是错误(在解释的脚本或插件中)会影响整个服务器。
您绝对可以使用 close-on-exec 标志来避免新启动的进程继承打开的文件或套接字(我不知道还有其他方法)。如果您使用 open(2)
打开文件,您可以在那个时刻通过将 O_CLOEXEC
添加到文件创建标志来设置标志。如果文件已经打开,您可以使用 fcntl()
设置它(如果您使用 fopen(3)
打开文件,您可以通过 fileno(3)
获取所需的文件描述符)。对于套接字,您还可以通过设置 SOCK_CLOEXEC
在使用 socket(2)
打开它时设置标志。没有设置此标志的文件将被您的程序生成的进程继承,无论是直接通过 fork + exec
还是该组合的任何其他 "disguise",如 system(3)
或 popen(3)
.
我有一个 TCP 服务器应用程序,它偶尔需要通过关闭它们然后在稍后打开它们来重新配置绑定端口。
应用程序还需要执行外部二进制文件并与之通信。目前这是使用 popen() 调用完成的。外部二进制运行时间可以跨越需要重新配置网络端口的时间段。
问题是,当主应用程序关闭一个端口时,它会被 popen 创建到 运行 二进制文件的 'forked' 进程占用。
这是有道理的(在 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) 提供的管道作为执行二进制文件的标准输入,当 CLOEXEC 关闭其他文件句柄时,该文件句柄是否保持打开状态。
有没有更好的方法来 运行 二进制文件,它不会导致分叉进程保持关闭的端口?
How to fork process without inheriting handles?
还有一个可能相关的问题不,您不能在没有 fork(2) followed by some execve(2) code (which is what popen
, posix_spawn
, and system
are doing). You'll better avoid popen
or system
and code the pipe
+fork
+execve
explicitly yourself (since you know which file descriptors should be kept and which to close(2), generally after the fork
and before the execve
in the child process...), see
(每个进程和程序,除了/sbin/init
和一些热插拔的东西,都是从fork
+ [=17=开始的]; 而你的 shell 对大多数命令不断使用 fork
+ execve
,除了像 cd
)
fork(2) call could be implemented by clone(2).
阅读一些好书,例如 高级 Linux 编程 在线免费提供的书 here. See also syscalls(2). Use (at least for debugging and to understand things) strace(1) and your debugger (gdb
). Study the source code of popen
and of system
in your free software libc (GNU libc or musl-libc),以及 shell 的源代码.
您几乎可以模仿execve(2) by a tricky sequence of mmap(2) (and related munmap
) calls, but not quite (in particular w.r.t. close-on-exec etc...). You'll probably need also to call the obsolete setcontext(3)(或编写等效的汇编代码)。
您可以考虑与专门的 shell 类服务器程序进行通信,执行 fork
和 execve
(请参阅我的 execicar.c for example and inspiration). Maybe you'll find daemon(3) 有用。
更好的选择可能是嵌入一些解释器(如 lua or guile) in your application and/or to dlopen(3) some plugin。缺点是错误(在解释的脚本或插件中)会影响整个服务器。
您绝对可以使用 close-on-exec 标志来避免新启动的进程继承打开的文件或套接字(我不知道还有其他方法)。如果您使用 open(2)
打开文件,您可以在那个时刻通过将 O_CLOEXEC
添加到文件创建标志来设置标志。如果文件已经打开,您可以使用 fcntl()
设置它(如果您使用 fopen(3)
打开文件,您可以通过 fileno(3)
获取所需的文件描述符)。对于套接字,您还可以通过设置 SOCK_CLOEXEC
在使用 socket(2)
打开它时设置标志。没有设置此标志的文件将被您的程序生成的进程继承,无论是直接通过 fork + exec
还是该组合的任何其他 "disguise",如 system(3)
或 popen(3)
.