C++ 从C+;启动Linux服务时避免套接字继承+;应用
我有一个Linux服务(守护进程),它有多个线程,并使用boost io_服务监听TCP套接字。当我在该套接字上收到某条消息时,我想启动另一个服务,例如C++ 从C+;启动Linux服务时避免套接字继承+;应用,c++,linux,sockets,boost,boost-asio,C++,Linux,Sockets,Boost,Boost Asio,我有一个Linux服务(守护进程),它有多个线程,并使用boost io_服务监听TCP套接字。当我在该套接字上收到某条消息时,我想启动另一个服务,例如/etc/init.d/corosync start 问题是,在启动服务后,当我退出自己的服务时,另一个服务从我自己的服务继承了套接字,并且它仍然处于一种奇怪的状态,我无法以通常的方式停止它 在退出我的进程“MonitorSipServer”之前,打开的套接字显示如下: netstat -anop |grep 144 tcp 0
/etc/init.d/corosync start
问题是,在启动服务后,当我退出自己的服务时,另一个服务从我自己的服务继承了套接字,并且它仍然处于一种奇怪的状态,我无法以通常的方式停止它
在退出我的进程“MonitorSipServer”之前,打开的套接字显示如下:
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)
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)
退出我的进程“MonitorSipServer”后,打开的套接字显示如下:
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)
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
环境进行了尝试。结果总是一样或更糟。
我最后的希望是Linuxsetsid
命令,但它也不起作用
任何帮助都将不胜感激。
当做
Jan如果您指的是套接字描述符本身被执行的子进程继承,这是不可取的,那么您可以在使用
socket(2)
创建套接字时传递SOCK\u CLOEXEC
,以确保在执行其他程序时关闭它们。(顺便说一下,这不会关闭连接,因为您的程序仍然有对套接字的引用。)
如果您使用的是某个更高级别的库,那么请检查是否有某种方法使其通过此标志,或者执行fcntl(sock_fd,F_SETFD,fcntl(sock_fd,F_GETFD)| fd_CLOEXEC)
在描述符创建后设置close-on-exec标志(如果可以的话)。(不过,在多线程环境中,fcntl(2)
方法是可行的,因为一些线程可以exec(3)
在创建套接字的点和设置了FD\u CLOEXEC
的点之间执行程序。)
如果上述操作不起作用,那么您可以在执行服务之前手动fork(2)
,然后关闭(2)
套接字描述符。SOCK\u CLOEXEC
的优点是,只有当exec*()
实际成功时,才会关闭套接字,这有时会使从错误中恢复更容易。此外,SOCK\u CLOEXEC
可以避免一些竞争,并且更难忘记关闭描述符
我有一个Linux服务(守护进程),它有多个线程,并使用boost io_服务监听TCP套接字。当我在该套接字上收到某条消息时,我想用/etc/init.d/corosync start启动另一个服务
对于使用systemd的现代Linux,您可能想了解一下。也就是说,主服务守护进程将只向unix套接字发送一个数据报(该数据报可能包含要显式传递给其他服务的文件描述符)。如果尚未启动,systemd将为您启动其他服务
使用systemd的好处是,您的服务不需要以root用户身份运行,就可以启动另一个服务,并且服务进程彼此完全隔离(没有继承任何东西,就像fork
ing一样)。Boost.Asio:
- 它要求程序准备并通知fork的
:io\u服务
未能使用此模式将导致未指定的行为。对于某些配置,父级将无法接收事件通知,因为它们被子级使用io\u服务\u.notify\u fork(boost::asio::io\u服务::fork\u prepare); 如果(fork()==0) { io\ U服务\通知\分支(boost::asio::io\ U服务::分支\子级); ... } 其他的 { io\ U服务\通知\分叉(boost::asio::io\ U服务::分叉\父级); ... }
- 该程序负责处理通过Boost.Asio的公共API访问的任何文件描述符。例如,如果父进程有一个打开的接受程序,则子进程需要在生成自己的子进程或替换进程映像之前显式调用。fork支持文档说明:
请注意,通过Boost.Asio的公共API访问的任何文件描述符(例如
、basic_socket
)在fork期间都不会更改。项目有责任根据需要对其进行管理posix::stream_descriptor
- Asio的fork支持对于多线程进程是不安全的。对于多线程进程,声明子进程只能在
和其中一个fork()
函数之间调用异步信号安全操作<代码>io_服务::notify_fork()不保证这一点,当前调用非异步信号安全操作exec()
话虽如此,我已经看到应用程序在多线程进程中使用Boost.Asio的
fork()
支持时没有观察到不良行为。但是,如果希望同时满足fork()
和Boost.Asio的要求,那么一个解决方案是在守护进程仍然是单线程的情况下为其提供fork。当父进程通过进程间通信通知子进程执行时,子进程将保持单线程,并执行fork()
和exec()
。回答中建议并演示了此解决方案。还请注意,在许多情况下,您无法控制所有文件描述符以及它们是否是使用SOCK\u CLOEXEC创建的,在这种情况下,您可以在fork()之后运行一个循环,关闭()所有描述符,直到sysconf(\u SC\u OPEN\u MAX)(如果您想不使用stdin/out/err或将其重定向到/dev/null,则可能从fd 3开始)目前,并非所有文件描述符都可以通过fd_CLOEXEC
set自动创建。在多线程应用程序中,另一个线程可能会在创建文件描述符之后,但在设置fd_CLOEXEC
之前分叉进程。H