我想使用 systemd 套接字激活来启动服务,只要在侦听套接字上收到 HTTP 请求即可。传入的消息并不重要,可以由 systemd 或其启动的服务丢弃。我已经能够做到这一点,但 HTTP 发送方会崩溃并出现错误Connection reset by peer
。我想满足发送 HTTP 客户端的要求,正确关闭套接字或 HTTP 交换。
首先,我有一个问题,即是否在文件中使用Accept=yes
或。例如:no
.socket
echo.socket
:
[Unit]
Description=Example echo socket
[Socket]
ListenStream=127.0.0.1:33300
Accept=yes
[Install]
WantedBy=sockets.target
在man systemd.socket
,建议
出于性能原因,建议仅以适合的方式编写新的守护进程
Accept=no
。
但是,我猜想名称Accept=
暗示了套接字上的传入连接是否已被接受(我猜是accept()
在内核级别调用),因为Accept=no
启动的服务需要接受和处理套接字上的连接。例如,请参阅此问题及其答案。如果我可以按照手册页的建议使用Accept=no
,我会非常高兴,但上述问题的答案暗示我需要调用某种 TCP 服务器,这是一个额外的学习曲线和复杂程度,如果可能的话,我可能会避免。(不过,任何类似的答案肯定都是可以接受的。)
因此,假设我使用Accept=yes
,并且我还有[email protected]
:
[Unit]
Description=echo service
[Service]
ExecStart=sh -c 'echo -e "HTTP/1.1 200 OK\nContent-Type: text/plain; charset=utf-8\nConnection: close\n\nOK"'
StandardInput=socket
StandardOutput=socket
发送 HTTP 请求可以激活服务,但是客户端不喜欢它:
$ curl 'http://127.0.0.1:33300'
OK
curl: (56) Recv failure: Connection reset by peer
$ journalctl --user -e
Jun 13 14:02:59 myhost systemd[906]: Started echo service (127.0.0.1:39908).
(例如,也请尝试python -c "import requests; r = requests.get('http://127.0.0.1:33300'); print(r.status_code)"
。)
不过,没有任何 HTTP 的简单程序socat
似乎可以毫无问题地退出。
$ socat - TCP:127.0.0.1:33300
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Connection: close
OK
我不知道这里的问题是什么,是 systemd 是否过于突然地关闭了 HTTP 交换的连接,还是 HTTP 交换缺少一些额外的关闭消息,还是其他什么。而且,如上所述,我仍然对Accept=no
解决方案感到好奇。