我有一个Linux服务(守护程序),它有多个线程并使用boost io_service监听TCP套接字。当我在该套接字上收到某个消息时,我想要启动另一个服务,例如/etc/init.d/corosync start
。
问题是,在启动服务后,当我退出自己的服务时,其他服务从我自己的服务继承了套接字,并且它仍处于一种奇怪的状态,我无法以通常的方式停止它。
退出我的流程之前" MonitorSipServer" open socket显示如下:
netstat -anop |grep 144
tcp 0 0 0.0.0.0:20144 0.0.0.0:* LISTEN 4480/MonitorSipServ off (0.00/0/0)
tcp 0 0 140.0.24.181:20144 140.0.101.75:47036 ESTABLISHED 4480/MonitorSipServ off (0.00/0/0)
退出我的流程" MonitorSipServer" open socket显示如下:
netstat -anop |grep 144
tcp 0 0 0.0.0.0:20144 0.0.0.0:* LISTEN 4502/corosync off (0.00/0/0)
tcp 0 0 140.0.24.181:20144 140.0.101.75:47036 ESTABLISHED 4502/corosync off (0.00/0/0)
我已尝试使用system
,popen
以及fork
+ execv
或execve
和null
环境。它总是相同的结果或更糟。
我最后的希望是Linux setsid
命令,但它也没有用。
任何帮助将不胜感激。 问候, 扬
答案 0 :(得分:5)
如果你指的是套接字描述符本身被exec的子进程继承,这是不可取的,那么你可以在用SOCK_CLOEXEC
创建套接字时传递socket(2)
确保在执行其他程序时关闭它们。 (顺便说一句,这不会关闭连接,因为你的程序仍然有对套接字的引用。)
如果您正在使用某个更高级别的库,那么检查是否有某种方法可以让它传递此标志,或者执行fcntl(sock_fd, F_SETFD, fcntl(sock_fd, F_GETFD) | FD_CLOEXEC)
在描述符之后设置close-on-exec标志。创建,如果你能够达到它。 (fcntl(2)
方法在多线程环境中可能很活泼,因为某些线程可以exec(3)
在创建套接字的点和设置FD_CLOEXEC
之间的程序。 )
如果以上方法不起作用,那么您可以在执行服务之前手动fork(2)
然后close(2)
套接字描述符。 SOCK_CLOEXEC
的优点是只有在exec*()
实际成功时才会关闭套接字,这有时可以更容易地从错误中恢复。此外,SOCK_CLOEXEC
可以避免某些比赛,并且更难忘记关闭描述符。
答案 1 :(得分:3)
Boost.Asio supports the fork()
system call:
它要求程序准备并通过io_service::notify_fork()
通知叉子的io_service
:
io_service_.notify_fork(boost::asio::io_service::fork_prepare);
if (fork() == 0)
{
io_service_.notify_fork(boost::asio::io_service::fork_child);
...
}
else
{
io_service_.notify_fork(boost::asio::io_service::fork_parent);
...
}
未能使用此模式会导致未指定的行为。对于某些配置,父级将无法接收事件通知,因为它们由孩子使用。
程序负责处理可通过Boost.Asio的公共API访问的任何文件描述符。例如,如果父级具有打开的acceptor
,则子级需要在生成其自己的子进程或替换进程映像之前显式调用acceptor::close()
。 fork支持文档说明:
请注意,通过Boost.Asio的公共API(例如
basic_socket<>
,posix::stream_descriptor
下面的描述符等)可访问的任何文件描述符都不会在fork中更改。该计划有责任根据需要进行管理。
fork()
指出子进程可能仅在fork()
和exec()
函数之一中调用异步信号安全操作。 io_service::notify_fork()
不提供此保证,当前implementation会调用非异步信号安全操作。话虽如此,我看到在多线程进程中使用Boost.Asio的fork()
支持时,应用程序没有观察到不良行为。但是,如果一个人希望满足fork()
和Boost.Asio的要求,那么一个解决方案是在守护进程仍处于单线程时进行派生。子进程将保持单线程,并在父进程通过进程间通信告知它时执行fork()
和exec()
。在this回答中建议并演示了此解决方案。
答案 2 :(得分:0)
我有一个Linux服务(守护程序),它有多个线程并使用boost io_service监听TCP套接字。当我在该套接字上收到某个消息时,我想要启动另一个服务,例如/etc/init.d/corosync start
对于使用systemd的现代Linux,您可能希望查看socket activation。也就是说,您的主服务守护程序只会将数据报发送到unix套接字(该数据报可能包含您希望显式传递给其他服务的文件描述符)。如果还没有开始,systemd会为你启动其他服务。
使用systemd的好处是您的服务不需要以root身份运行,以便能够启动另一个服务,并且服务进程彼此完全隔离(没有像fork
那样的任何继承荷兰国际集团)。