我一直在try 用Rust制作一个简单的守护进程,它将使用tcp_流监听端口并打印消息.然而,我遇到了两个问题:

1) 如果我的守护进程使用println!,它崩溃了.如果我删除所有关于println的内容!,守护进程可以工作.在创建守护进程时,stdout/stdin是如何工作的?

One source I found on the Rust mailing list表示,"对于现代的init系统,比如systemd或launchctl,这可以很好地工作,应用程序开发人员不必关心Daemonization,也可以通过stdout简单地完成日志(log)记录."这是什么意思?

2) 当我在非守护程序模式下运行下面的代码时,curls不会立即返回(运行类似于$ curl -XPOST localhost:9337 -d 'hi'的代码).我得杀了curl服务器才能打印东西.不会自动关闭连接吗?发送的字节在发送后,而不是在连接关闭后,不应该对服务器可用吗?

extern crate getopts;
use getopts::{optflag,getopts};
use std::io::Command;
use std::io::net::tcp::{TcpListener};
use std::io::{Acceptor,Listener};
use std::os;

fn main() {
    let args: Vec<String> = os::args();
    let opts = [
        optflag("d", "daemon", "conver this into a daemon"),
    ];
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_string()) }
    };

    // Create a daemon? if necessary
    if matches.opt_present("d") {
        let child = Command::new(args[0].as_slice())
                            .detached().spawn().unwrap();
        println!("Created child: {}", child.id());

        // Do I wrap this in unsafe?
        child.forget();
        return;
    }

    let listener = TcpListener::bind("127.0.0.1", 9337u16).ok().expect("Failed to bind");
    let mut acceptor = listener.listen().ok().expect("Could not listen");

    loop {
        let mut tcp_stream = acceptor.accept().ok().expect("Could not accept connection");
        println!("Accepted new connection");

        let message = tcp_stream.read_to_string().unwrap();
        println!("Received message {}", message);
    }
}

推荐答案

这是什么意思?

他们的意思是,你不应该做任何像Forking 这样的花哨的事情来创建一个守护程序.您的程序应该只是工作,将其操作直接记录到STDUT中,而像StReD或ActudiCtl这样的init系统将自动处理所有其他事项,包括启动、关机、日志(log)重定向、生命周期管理等.认真考虑这种方法,因为它会使程序变得简单得多.

不过,正确创建守护进程并不简单.你必须Forking 进程,关闭并设置新的文件描述符,调整进程组,添加信号处理程序等等.在谷歌上搜索"fork daemon"之类的东西,会得到很多关于如何创建守护进程的文章,你会发现这不是一项容易的任务.当然,您可以在Rust中执行类似的操作,因为它通过libc crate expose 所有必要的系统调用.不过,可能有一些警告:例如,我不确定Rust runtime对fork()系统调用会有什么react .

至于为什么你的"守护进程"在使用println!()时会失败,我怀疑这是因为你从你的子进程中分离,它的stdio句柄会自动关闭,而Rust I/O routine 对此不满意,并触发任务失败.

Rust相关问答推荐

即使参数和结果具有相同类型,fn的TypId也会不同

在不重写/专门化整个函数的情况下添加单个匹配手臂到特征的方法?

有没有一种惯用的方法来判断VEC中是否存在变体?

是否可以在不切换到下一个位置的情况下获得迭代器值:

变量需要parse()中的显式类型

考虑到Rust不允许多个可变引用,类似PyTorch的自动区分如何在Rust中工作?

为什么 vec![Vec::with_capacity(n)] 为子向量创建 0 容量?

从管道读取后重置标准输入

如何将一个矩阵的列分配给另一个矩阵,纳尔代数?

详尽的匹配模式绑定

如何在 Rust 中将函数项变成函数指针

在没有任何同步的情况下以非原子方式更新由宽松原子操作 Select 的值是否安全?

Rust 中指向自身的引用如何工作?

从光标位置旋转精灵

如何在 Rust 的 Hyper 异步闭包中从外部范围正确读取字符串值

&str 的编译时拆分是否可能?

如何在 Rust 中创建最后一个元素是可变长度数组的 struct ?

使用 `.` 将 T 转换为 &mut T?

有没有办法阻止 rust-analyzer 使非活动代码变暗?

守卫如何影响匹配语句?