sockets - 为什么 `forever` 意味着此代码不从套接字读取或打印到标准输出?

标签 sockets haskell systemd unix-socket

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

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

部署触发器.socket:

[Socket]
ListenStream=/var/run/deploy-trigger.socket

[Install]
WantedBy=sockets.target

部署触发器服务:
[Service]
ExecStart=/home/user4301448/.local/bin/deploy-trigger-exe
StartLimitInterval=0

主文件
{-# 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再次 ing 并向套接字发送一些文本会在日志中打印以下内容:
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 套接字的无能。任何关于我误解的支持信息的答案,纠正我的达夫术语将是一个奖励。

最佳答案

似乎是因为 stdout未连接到终端,putStrLn 的小输出保持缓冲,因此不会出现在日志中。这可以通过调用 hFlush 来解决。定期,例如:

main = withSocketsDo $ forever $
  getActivatedSockets >>= processSocks >>= \_ -> hFlush stdout

关于sockets - 为什么 `forever` 意味着此代码不从套接字读取或打印到标准输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48492025/

相关文章:

sockets - 使用一个套接字进行对等通信

Java Socket 服务器应用程序 : Getting the packet after long delay

node.js - 如何将属性关联到Redis Store中的socket.io对象?

haskell - 无法创建 Num 的派生实例

unit-testing - 使用 "stack test"时,我的 hspec 测试输出未着色

linux - MongoDB服务重启后失败

docker - 不带systemd的CentOS 7 Docker镜像中的服务

java.io.BufferedReader.readLine() 是非阻塞的

haskell - 如何在 Haskell 中并行化从 stdin 延迟读取信息?

linux - 如何从 systemd 配置文件中的函数输出设置 ExecStart?