【问题标题】:Rust Daemon best practicesRust 守护进程最佳实践
【发布时间】:2020-08-10 01:46:13
【问题描述】:

我在为 rust 中的 unix 套接字服务器创建守护程序时遇到了困难。在像 node.js 这样的语言中,我只会产生一个分离的进程。但生锈似乎更具挑战性。

(所有工作都在 unix 环境中)

这是一个简单的例子。我写了:

use std::os::unix::net::{UnixListener, UnixStream};

use std::path::{Path};
use std::io::{Read, Write};
use std::{fs};
use std::thread;


fn handle_stream(mut stream: UnixStream) {
    
    loop {
        let mut read = [0; 1028];
        match stream.read(&mut read) {
            Ok(n) => {
                if n == 0 {
                    // connection was closed
                    println!("connection closed?");
                    break;
                }
                let msg = String::from_utf8(read.to_vec()).unwrap();
                println!("SERVER: {} received from remote client.", msg);

                match stream.write_all(&read[0..n]) {
                    Ok(_) => {}
                    Err(e) => println!("Error writing to socket: {}", e),
                }
            }
            Err(err) => {
                panic!(err);
            }
        }
    }
    println!("SERVER: Ending connection with client.");
}

fn server_start() {
    
    // remove existing sock if exists
    let _did_remove = fs::remove_file("/Users/tom/desktop/app.sock");

    // socket location
    let socket_file = "/Users/tom/desktop/app.sock";
    let socket = Path::new(socket_file);

    // Bind to socket
    let listener = match UnixListener::bind(&socket) {
        Err(_) => panic!("failed to bind socket"),
        Ok(stream) => stream,
    };

    println!("Server started, waiting for clients");

    for conn in listener.incoming() {
        match conn {
            Ok(stream) => {
                // spawn a new thread for each incoming
                thread::spawn(|| handle_stream(stream));
            }
            Err(err) => {
                println!("Error connecting to client: {}", err);
                break;
            }
        }
    }
}

fn main() {

    server_start();
}

【问题讨论】:

  • 我希望,我实际上已经读过这篇文章太多次了。我猜 rust 在该帖子得到答复后从 Command 中删除了分离的方法。
  • 你确定你需要一个真正的守护进程而不是一个简单的 systemd 服务(假设你在 Linux 上)?后者更容易,并且在大多数情况下都可以正常工作。例如,请参阅medium.com/@benmorel/…
  • 这看起来像要走的路,我稍后会发布一个示例
  • 我赞同@kreo 不打扰的建议。 Systemd 文档discourages self-daemonization:“对于开发新型守护进程,不需要执行为 SysV 守护进程推荐的初始化步骤。像 systemd 这样的新型初始化系统使它们都变得多余。此外,由于其中一些步骤干扰init系统的进程监控、文件描述符传递等功能,作为新式服务运行时建议不要执行。"

标签: unix rust daemon


【解决方案1】:

根据 cmets 中的消息,我决定使用 systemd 服务而不是创建自己的守护进程。这似乎是管理后台任务的理想方式。我已经编辑了顶部代码,以便它对答案有意义。

Systemd - linux

您需要创建一个.service 文件并将其放在您的systemd 守护程序目录中。例如:/etc/systemd/system/test.service

然后更新文件权限:

sudo chmod 644 /etc/systemd/system/test.service

启动您的服务:

sudo systemctl start service_name

服务代码:

[Unit]
Description=Test service
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=username
ExecStart=/usr/bin/env test

[Install]
WantedBy=multi-user.target

Launchctl - macOS

对于 macOS,我们需要创建一个 .plist 文件并将其放置在启动守护进程目录中。例如:/Library/LaunchDaemons/test.plist

接下来更新文件的权限:

sudo chown root:wheel /Library/LaunchDaemons/com.test.daemon.plist

加载守护进程:

launchctl load /Library/LaunchDaemons/com.test.daemon.plist

启动守护进程:

launchctl start /Library/LaunchDaemons/com.test.daemon

Plist 代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
        <string>com.test.daemon</string>
    <key>ServiceDescription</key>
        <string>Test Server</string>
    <key>ProgramArguments</key>
        <array>             
            <string>/Users/tom/desktop/test/target/debug/test</string>
        </array>
    <key>RunAtLoad</key>
        <false/>
</dict>
</plist>

【讨论】:

    猜你喜欢
    • 2010-10-09
    • 2018-03-10
    • 2010-09-24
    • 2011-12-16
    • 1970-01-01
    • 2010-11-18
    • 2011-10-31
    • 2018-08-26
    • 2017-11-16
    相关资源
    最近更新 更多