Unix 最佳做法
我在rust中为unix套接字服务器创建守护程序时遇到困难。在node.js这样的语言中,我只需要生成一个分离的进程。但生锈似乎更具挑战性 (所有工作都在unix环境中进行) 下面是一个简单的例子。我写道:Unix 最佳做法,unix,rust,daemon,Unix,Rust,Daemon,我在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 handl
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();
}
根据注释中的消息,我决定使用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
启动CTL-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
启动守护程序:
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>
标签
com.test.daemon
服务描述
测试服务器
程序参数
/用户/tom/desktop/test/target/debug/test
运行负荷
这是否回答了您的问题?我真希望,我已经读了很多次了。我猜rust在该帖子被回复后从命令中删除了分离的方法。你确定你需要一个实际的守护进程而不是一个简单的systemd服务(假设你在Linux上)?后者更简单,在大多数情况下都可以正常工作。例如,如果这看起来像是一条路要走,我将在稍后发布一个例子,我是second@kreo不打扰的建议。系统文件:“为了开发一个新型的守护进程,不需要执行为SysV守护进程推荐的任何初始化步骤。像systemd这样的新型init系统使它们都是冗余的。此外,由于其中一些步骤会干扰进程监视、文件描述符传递和init系统的其他功能,因此建议在作为新型服务运行时不要执行这些步骤。”