我在 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();
}
Run Code Online (Sandbox Code Playgroud)
根据评论中的消息,我决定使用 systemd 服务,而不是创建自己的守护进程。这似乎是管理后台任务的理想方式。我已经编辑了顶部代码,以便它与答案有意义。
系统-Linux
您需要创建一个.service文件并将其放置在您的 systemd 守护进程目录中。例如:/etc/systemd/system/test.service
然后更新文件权限:
sudo chmod 644 /etc/systemd/system/test.service
Run Code Online (Sandbox Code Playgroud)
要启动您的服务:
sudo systemctl start service_name
Run Code Online (Sandbox Code Playgroud)
服务代码:
[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
Run Code Online (Sandbox Code Playgroud)
Launchctl - macOS
对于 macOS,我们需要创建一个.plist文件并将其放置在启动守护程序目录中。例如:/Library/LaunchDaemons/test.plist
接下来更新文件的权限:
sudo chown root:wheel /Library/LaunchDaemons/com.test.daemon.plist
Run Code Online (Sandbox Code Playgroud)
加载守护进程:
launchctl load /Library/LaunchDaemons/com.test.daemon.plist
Run Code Online (Sandbox Code Playgroud)
启动守护进程:
launchctl start /Library/LaunchDaemons/com.test.daemon
Run Code Online (Sandbox Code Playgroud)
列表代码:
<?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>
Run Code Online (Sandbox Code Playgroud)