为什么`永远`意味着这段代码不会从套接字读取或打印到标准输出?(Why does `forever` mean this code doesn't read from a socket or

编程入门 行业动态 更新时间:2024-10-28 07:33:18
为什么`永远`意味着这段代码不会从套接字读取或打印到标准输出?(Why does `forever` mean this code doesn't read from a socket or print to stdout?)

我在Haskell中编写了一个systemd套接字激活服务。 这个想法是服务应该在消息发送到它的套接字时自动启动,服务应该处理在套接字上等待的所有消息,然后退出。

注意:处理所有等待消息(而不是永久运行)后服务应该关闭的原因是套接字激活之间应该有几个小时或几天的时间。

部署-trigger.socket:

[Socket] ListenStream=/var/run/deploy-trigger.socket [Install] WantedBy=sockets.target

部署-trigger.service:

[Service] ExecStart=/home/user4301448/.local/bin/deploy-trigger-exe StartLimitInterval=0

Main.hs

{-# LANGUAGE OverloadedStrings #-} module Main where import Control.Monad (forever) import qualified Data.ByteString.Char8 as BS (putStrLn) import Data.Foldable (foldl') import Network.Socket (withSocketsDo, accept, close, SockAddr(SockAddrUnix), Socket) import Network.Socket.ByteString (recv) import Network.Socket.Activation (getActivatedSockets) import System.Exit (exitWith, ExitCode(..)) main :: IO () main = withSocketsDo $ forever $ getActivatedSockets >>= processSocks processSocks :: Maybe [Socket] -> IO () processSocks (Just socks) = do putStrLn "Got socket(s)." traverse_ (\sock -> accept sock >>= printMsgFromSock) socks putStrLn "Finished processing socket(s)." processSocks Nothing = do putStrLn "Received no socket(s)." exitWith ExitSuccess printMsgFromSock :: (Socket, SockAddr) -> IO () printMsgFromSock (sock, sockaddr) = do msg <- recv sock 2048 case sockaddr of SockAddrUnix s -> putStrLn ("Printing message from socket: " ++ s) _ -> putStrLn "Printing message from something that is not a UNIX socket." BS.putStrLn msg close sock

编译时(并使用stack install ),然后通过使用以下命令向套接字发送一些文本来激活:

printf 'Hello world\r\n' | nc -U /var/run/deploy-trigger.socket

以下是打印到systemd日志(我正在使用journalctl -f来观看日志):

systemd[1]: Starting deploy-trigger.service...

没有其他印刷品; 该过程将永久运行并最大化所有计算机的CPU核心。 为什么会发生这种情况,并且是否有办法将行为改变为第一段中描述的行为?

将main更改为以下内容:

main = withSocketsDo $ getActivatedSockets >>= processSocks

从而forever删除,再次stack install并发送一些文本到套接字将以下内容打印到日志中:

systemd[1]: Starting deploy-trigger.service... deploy-trigger-exe[14800]: Got socket(s). deploy-trigger-exe[14800]: Printing message from socket: deploy-trigger-exe[14800]: Hello world deploy-trigger-exe[14800]: Finished processing socket(s). systemd[1]: Started deploy-trigger.service.

deploy-trigger-exe然后干净地退出。 这样做的缺点是二进制似乎是由systemd对发送到套接字的每条消息运行的,这是不可取的。

注意:我怀疑这个问题根源于我对UNIX套接字的无能。 任何有关我误解的支持信息的答案,纠正我的duff术语将是一项奖励。

I have written a systemd socket activated service in Haskell. The idea is the service should be started automatically when a message is sent to its socket, the service should process all messages waiting on the socket and then exit.

Note: the reason the service should close after processing all waiting messages (as opposed to running forever) is there shall be several hours or days between socket activations.

deploy-trigger.socket:

[Socket] ListenStream=/var/run/deploy-trigger.socket [Install] WantedBy=sockets.target

deploy-trigger.service:

[Service] ExecStart=/home/user4301448/.local/bin/deploy-trigger-exe StartLimitInterval=0

Main.hs

{-# LANGUAGE OverloadedStrings #-} module Main where import Control.Monad (forever) import qualified Data.ByteString.Char8 as BS (putStrLn) import Data.Foldable (foldl') import Network.Socket (withSocketsDo, accept, close, SockAddr(SockAddrUnix), Socket) import Network.Socket.ByteString (recv) import Network.Socket.Activation (getActivatedSockets) import System.Exit (exitWith, ExitCode(..)) main :: IO () main = withSocketsDo $ forever $ getActivatedSockets >>= processSocks processSocks :: Maybe [Socket] -> IO () processSocks (Just socks) = do putStrLn "Got socket(s)." traverse_ (\sock -> accept sock >>= printMsgFromSock) socks putStrLn "Finished processing socket(s)." processSocks Nothing = do putStrLn "Received no socket(s)." exitWith ExitSuccess printMsgFromSock :: (Socket, SockAddr) -> IO () printMsgFromSock (sock, sockaddr) = do msg <- recv sock 2048 case sockaddr of SockAddrUnix s -> putStrLn ("Printing message from socket: " ++ s) _ -> putStrLn "Printing message from something that is not a UNIX socket." BS.putStrLn msg close sock

When compiled (and installed with stack install), then activated by sending some text to the socket using the following command:

printf 'Hello world\r\n' | nc -U /var/run/deploy-trigger.socket

the following is printed to the systemd journal (I'm using journalctl -f to watch the logs):

systemd[1]: Starting deploy-trigger.service...

nothing else is printed; the process runs forever and maxes out all the computer's CPU cores. Why does this happen and is there a way to change the behaviour to that described in the first paragraph?

Changing main to the following:

main = withSocketsDo $ getActivatedSockets >>= processSocks

thus removing forever, stack installing again and sending some text to the socket prints the following to the journal:

systemd[1]: Starting deploy-trigger.service... deploy-trigger-exe[14800]: Got socket(s). deploy-trigger-exe[14800]: Printing message from socket: deploy-trigger-exe[14800]: Hello world deploy-trigger-exe[14800]: Finished processing socket(s). systemd[1]: Started deploy-trigger.service.

deploy-trigger-exe then exits cleanly. The downside to this is the binary appears to be run by systemd for every message sent to the socket, which is not desirable.

Note: I suspect the issue is rooted in my incompetence regarding UNIX sockets. Any answers with supporting information on what I'm misunderstanding, correcting my duff terminology would be a bonus.

更多推荐

本文发布于:2023-04-27 21:50:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1328601.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:这段   代码   标准   code   stdout

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!