编写一个Unix守护进程

3
我正在尝试在Unix中编写守护进程。我知道如何让守护进程启动和运行。现在,我希望当我在shell中输入命令并将其定向到守护进程时,它能够响应。
例如:
假设守护进程的名称为“mydaemon”。
在终端1中,我键入mydaemon xxx。
在终端2中,我键入mydaemon yyy。
"mydaemon" 应该能够接收参数 "xxx" 和 "yyy"。

你的意思是在第一次启动守护进程时就能够传递命令,还是指在已经启动并运行的守护进程中,连续调用“mydaemon”以向已运行的进程发送指令? - Matt
1
我的意思是对“mydaemon”的连续调用会向已经运行的进程发送指令。 - user1801900
2个回答

1

如果我正确理解了您的问题,那么您必须将其作为应用程序级别的构造来完成。也就是说,这是特定于您的程序的某些东西,您需要自己编写代码。

我会采取的方法是编写“mydaemon”,并将其视为包装器:它检查进程表或pid文件,以查看是否已经运行了“mydaemon”。如果没有,则fork / exec您的新守护程序。如果有,则将参数发送给它。

对于“将参数发送给它”,我会使用命名管道,就像这里所解释的那样: 什么是命名管道?基本上,您可以将命名管道视为类似于“stdin”,除了它们在系统的其余部分中显示为文件,因此您可以在运行的“mydaemon”中打开它们并检查它们的输入。

最后,值得注意的是,所有这些检查是否运行-send-to-pipe的内容都可以在您的守护程序中使用*nix OS的API完成,也可以通过使用例如'ps','echo'等脚本来完成...


谢谢,我这里还有一个问题,假设我想返回新请求“mydaemon yyy”,表示您的请求已被接受,我可以在命名管道中写入内容并在另一端读取吗? - user1801900
我认为一个管道不足以完成任务 - 您可以使用多个管道,但是使用Unix套接字http://beej.us/guide/bgipc/output/html/multipage/unixsock.html可能更好 - 特别是请看文章末尾的socketpair()的描述。使用Unix套接字感觉更像使用完整的网络套接字,这可能是一个优势 - 几乎可以轻松地将您的守护程序转换为网络服务 - 并且(如果您做得正确)您可以在您的守护程序和任何其他程序之间进行全双工异步通信。 - Matt

0

在Linux中最简单、最常见、最强大的方法是使用systemd socket服务。

  • /usr/lib/systemd/system/yoursoftware.socket的示例内容:
    [Unit]
    Description=这是你的软件描述
    Before=yoursoftware.service
    
    [Socket]
    ListenStream=/run/yoursoftware.sock
    Service=yourservicename.service
    # 例如:使用SocketMode=0666为所有人提供读写访问权限
    # 例如:使用SocketMode=0640为root提供读写访问权限,为SocketGroup提供只读访问权限
    SocketMode=0660
    SocketUser=root
    # 使用socket组仅授予特定进程访问权限
    SocketGroup=root
    
    [Install]
    WantedBy=sockets.target
    
    • 注意:如果您正在创建本地用户守护程序而不是根守护程序,则您的systemd文件位于/usr/lib/systemd/user/(请参见pulseaudio.socket)或~/.config/systemd/user/,并且您的套接字位于/run/usr/$(id -u)/yoursoftware.sock(请注意,您实际上无法在systemd中的路径名中使用命令替换。)
  • /lib/systemd/system/yoursoftware.service的示例内容:
    [Unit]
    Description=这是你的软件描述
    Requires=yoursoftware.socket
    
    [Service]
    ExecStart=/usr/local/bin/yoursoftware --daemon --yourarg yourvalue
    KillMode=process
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target
    Also=yoursoftware.socket
    
  • 以root身份运行systemctl daemon-reload && systemctl enable yoursoftware.socket yoursoftware.service
    • 如果您正在创建要作为本地用户运行的服务,则使用systemctl --user daemon-reload && systemctl --user enable yoursoftware.socket yoursoftware.service
  • 在C中,软件的功能示例将太长,因此这里提供了NodeJS的示例。这是/usr/local/bin/yoursoftware
    #!/usr/bin/env node
    var SOCKET_PATH = "/run/yoursoftware.sock";
    function errorHandle(e) {
      if (e) console.error(e), process.exit(1);
    }
    if (process.argv[0] === "--daemon") {
      var logFile = require("fs").createWriteStream(
        "/var/log/yoursoftware.log", {flags: "a"});
      require('net').createServer(errorHandle)
        .listen(SOCKET_PATH, s => s.pipe(logFile));
    } else process.stdin.pipe(
      require('net')
        .createConnection(SOCKET_PATH, errorHandle)
    );
    
  • 在上面的示例中,您可以同时运行许多yoursoftware实例,并且每个实例的stdin都会通过管道传输到守护程序,守护程序将接收到的所有内容附加到日志文件中。
对于非Linux操作系统和没有systemd的发行版,您将使用(通常是shell脚本)启动系统在启动时开始进程,当守护进程出现问题时,用户会收到类似错误消息:无法连接到套接字/run/yoursoftware.sock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接