创建一个侦听端口的简单Rust守护程序

时间:2014-10-14 06:58:36

标签: tcp process daemon rust

我一直在尝试在Rust中创建一个简单的守护进程,它将使用tcp_stream监听端口并打印该消息。但是,我遇到了两个问题:

1)如果我的守护进程使用println !,它会崩溃。如果我删除了所有提到的println !,那么守护程序就可以了。 stdout / stdin在制作守护进程时如何工作?

One source I found on the Rust mailing list说"对于现代的init系统,例如systemd或launchctl,这非常好用,应用程序开发人员也不必关心守护进程,并且只需通过stdout完成日志记录。 "这是什么意思?

2)当我在非守护进程模式下运行下面的代码时,卷发不会立即返回(运行$ curl -XPOST localhost:9337 -d 'hi'之类的东西)。我必须杀死卷曲服务器打印一些东西。不会自动关闭连接吗?服务器发送后发送的字节是否可用,而不是在连接关闭后?

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);
    }
}

2 个答案:

答案 0 :(得分:3)

  

这是什么意思?

他们的意思是你不应该做任何想要创建守护程序的事情。您的程序应该正常工作,将其操作直接记录到stdout,而systemd或launchctl等init系统将自动处理其他所有内容,包括启动,关闭,日志重定向,生命周期管理等。认真考虑这种方法,因为它会使您的程序更简单

然而,正确地创建守护进程并不简单。您必须分叉进程,关闭并设置新的文件描述符,调整进程组,添加信号处理程序等。谷歌搜索"fork daemon"之类的内容提供了很多关于如何创建守护进程的文章,而can see这不是一件容易的事。当然,你可以在Rust中做这样的事情,因为它通过libc crate暴露了所有必要的系统调用。但是可能有一些警告:例如,我不确定Rust运行时对fork()系统调用的反应。

至于为什么你的“守护进程”在你使用println!()时失败了,我怀疑它是因为你从你的子进程分离并且它的stdio句柄被自动关闭,而Rust I / O例程对它不满意并触发任务失败。

答案 1 :(得分:0)

使用https://docs.rs/daemonize/0.4.1/daemonize/板条箱为您创建守护程序来处理大多数棘手的事情吗?