我在远程停止服务时遇到问题。
我有一个简单的套接字/服务对:
# /etc/systemd/system/foo.socket
[Unit]
Description=The socket
[Socket]
ListenStream=11111
# /etc/systemd/system/foo.service
[Unit]
Description=The service
[Service]
Type=simple
ExecStart=sleep infinity
之后systemctl start foo.socket
看起来像:
foo.socket: active (listening)
foo.service: inactive (dead)
然后与另一台机器建立连接netcat 10.10.1.16 11111
,我们得到:
foo.socket: active (running)
foo.service: active (running)
完美的!
现在,如果我们终止连接(SIGTERM
to netcat
),我们会得到:
foo.socket: active (running)
foo.service: active (running)
但我预计:
foo.socket: active (listening)
foo.service: inactive (dead)
如何使用TCP连接远程停止服务?
我试过了:
Accept=yes
和[email protected]
- 提供服务
PartOf=foo.socket
或Requires=foo.socket
StandardInput=socket
以及标准输出和标准错误。
答案1
而不是/bin/sleep infinity
你想运行不同的东西:
[Service]
Type=simple
ExecStart=foo
StandardInput=socket
其中任何一个在哪里foo
:
#include <stdio.h>
int main(int, char**) {
char buf[256];
while(scanf("%255s",buf) > 0) {}
return 0;
}
#!/bin/sh
while read line; do
echo "$line"
done < "${1:-/dev/stdin}"
#!/usr/bin/python3
import sys
for line in sys.stdin:
pass
#!/usr/bin/perl
while (<>) {
if (eof()) { exit }
}
解释:
当您使用某个Type=simple
服务时,该进程一结束,该服务就会停止ExecStart
。因此,即使您关闭连接,服务也不会停止,因为应用程序不知道它应该退出。 Systemd 不会发送 SIGTERM,也不需要发送。
相反,我提供了四个ExecStart
执行相同操作的进程的实现(C、sh、python、perl):从 stdin 读取,直到 stdin 不再可用。当连接关闭时,流结束,这意味着 stdin 结束。因此,只需继续阅读 stdin 直到得到 EOF,然后退出。一旦您的进程退出,服务就会停止。
内置函数
如果您不想部署上述脚本之一,请使用侦听 stdin 并在 EOF 时退出的内置工具之一。副作用是他们可能真的做了一些事情。我第一个能想到的是grep -
。EXIT_FAILURE
如果它不匹配任何内容,它就会返回,因此在它前面加上前缀-
,以确保每次关闭连接时不会导致服务失败。
[Service]
Type=simple
ExecStart=-/bin/grep -
StandardInput=socket
如果您认为利用这个过程可能很有趣,那么也许可以让您的联系做一些有用的事情。我能想到的第二个程序是python3
。因此,现在您可以让整个口译员闲置待命,等待为您做点什么。如果您不添加一些沙箱,这可能会很危险,但 systemd 可以使用DynamicUser=
.
[Service]
Type=simple
ExecStart=/usr/bin/python3
StandardInput=socket
DynamicUser=yes
如果您希望在客户端确认连接已建立,也许可以考虑使用cat
.首先创建一些样板文本:
echo "established" > /usr/local/etc/simple/start_text
然后告诉 systemd 对该文本进行 cat 处理,然后是 stdin
[Service]
Type=simple
ExecStart=-cat /usr/local/etc/simple/start_text -
StandardInput=socket
现在,netcat
当连接建立时,您的客户端将获得打印输出。
还值得注意的是,您应该使用Accept=yes
和[email protected]
。否则,systemd 将期望您的应用程序可以接受传入连接,但这里的情况并非如此。