进一步阅读

进一步阅读

我有一系列手动启动的命令,但不适用于 systemd (HOST_TX):

主持人_接收

nc -v -l -p 5006 

监听 [0.0.0.0](系列 0,端口 5006)

主持人_TX

 /opt/sendtofifo.sh > /tmp/tofifo1                    # in a shell
 nc -v -w 3 HOST_RX 5006 < /tmp/tofifo1   # in a second shell

如果我不使用 fifo,我可以手动发送:

/bin/bash -xc '/opt/sendtofifo.sh | /bin/nc -v -T lowdelay  HOST_RX 5006'

当 HOST_RX 停止监听时,两个命令都会退出 clean,而不是 systemd 继续运行,/opt/sendtofifo.sh忽略 的状态nc

尝试按如下方式设置 systemd 服务:

[Service]
Type=simple
RestartSec=2
ExecStart=/bin/bash -xc '/opt/sendtofifo.sh | /bin/nc -v -T lowdelay  HOST_RX 5006'
Restart=always

这首先有效:

root@rx(boot:ro,root:rw):/home/pi# systemctl status  rx_rc.service
● rx_rc.service - RX RC Service
   Loaded: loaded (/etc/systemd/system/rx_rc.service; static; vendor preset: enabled)
   Active: active (running) since Tue 2020-06-09 14:34:52 CEST; 4s ago
 Main PID: 28649 (bash)
   CGroup: /system.slice/rx_rc.service
           ├─28649 /bin/bash -xc /opt/sendtofifo.sh  | /bin/nc -v -T lowdelay  10.11.10.11 5006; exit
           ├─28650 /opt/sendtofifo.sh 
           └─28651 /bin/nc -v -T lowdelay 10.11.10.11 5006

现在如果 HOST_RX 关闭连接我得到:

● rx_rc.service - RX RC Service
   Loaded: loaded (/etc/systemd/system/rx_rc.service; static; vendor preset: enabled)
   Active: active (running) since Tue 2020-06-09 14:34:52 CEST; 1min 11s ago
 Main PID: 28649 (bash)
   CGroup: /system.slice/rx_rc.service
           ├─28649 /bin/bash -xc /opt/sendtofifo.sh | /bin/nc -v -T lowdelay  10.11.10.11 5006; exit
           └─28650 /opt/sendtofifo.sh

nc如果失败有办法重新启动服务吗?

对评论的回应

/opt/sendtofifo.sh 进程的 strace 输出

nanosleep({tv_sec=0, tv_nsec=200000000}, NULL) = 0
write(1, "\0\0\f\0\4\200\0\0\30\0\0\0\264\277\0\0\271\315\6\0002\364\301\22\257\4 \0\315", 29) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=1589, si_uid=0} ---
nanosleep({tv_sec=0, tv_nsec=200000000}, NULL) = 0

答案1

明显但错误的回答是“但是SIGPIPE 将要导致你的程序被终止,因为这就是它的作用SIGPIPERestart=always因此设置将导致它重新启动。”。

这是错误的,因为 systemd 默认执行服务时会SIGPIPE忽略信号。因此,服务进程及其子进程(在本例中是解释脚本的 shell)只需忽略任何SIGPIPEs 并继续。

为什么systemd要这么做呢?正是因为systemd-journald.在早期版本的 systemd 中,当systemd-journald崩溃或以其他方式终止时,向其发送标准输出和标准错误的所有服务都会获得一个SIGPIPE.如果不忽略,这将导致系统上的几乎所有服务都被 关闭systemd-journald,至少可以说这是一种不幸的情况。 systemd 的人没有从 daemontools 中吸取教训,daemontoolssvscan确保它保留“主”服务和“日志”服务之间管道的打开文件描述符,以便“主”服务SIGPIPE在“日志”服务时永远不会出现虚假的情况。服务因任何原因重新启动。

几年后,他们最终流行起来,systemd 现在将打开的文件描述符保存到连接服务的管道中systemd-journald,尽管它以一种相当迂回的方式做到这一点,即让进程将它们选择的文件描述符注入到进程 #1 中。不再需要忽略SIGPIPE标准,因为不再需要掩盖原始问题。

IgnoreSIGPIPE但服务单元中的设置的默认值仍然保留yes

将其更改为no您的服务单位。

进一步阅读

相关内容