read_to_end方法永远不会返回UnixStream

时间:2018-06-12 13:38:58

标签: rust unix-socket

我正在使用Unix域套接字来交流进程的应用程序。为此,我在标准库中使用UnixListenerUnixStream类型。

我发现根据我读取数据的方式,该过程可能会挂起。调试后我发现它取决于我是使用read还是read_to_end从套接字中检索数据。使用read工作正常,而使用read_to_end会使调用进程挂起,直到我终止其他进程(此时数据实际被读取)。这似乎是刷新缓冲区的问题,尽管文档没有提到任何类型。

这是问题的一个有效例子:

use std::env;
use std::io::{Read, Write};
use std::os::unix::net::{UnixListener, UnixStream};
use std::thread;

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

fn start_server(address: String) {
    let listener = UnixListener::bind(&address).unwrap();

    // accept connections and process them, spawning a new thread for each one
    for connection in listener.incoming() {
        match connection {
            Ok(stream) => {
                /* connection succeeded */
                thread::spawn(|| handle_client(stream));
            }
            Err(err) => {
                /* connection failed */
                println!("Error connecting to client: {}", err);
                break;
            }
        }
    }
}

fn start_client(address: String, msg: String) {
    let mut socket = match UnixStream::connect(&address) {
        Ok(sock) => sock,
        Err(e) => {
            println!("Couldn't connect! {}.", e);
            return;
        }
    };
    let request = msg.into_bytes();
    match socket.write_all(&request) {
        Ok(_) => {}
        Err(e) => println!("Error writing to socket: {}", e),
    }

    // This variant works
    // let mut read = [0; 1028];
    // match socket.read(&mut read) {

    // This variant does not work.
    let mut read = Vec::with_capacity(1024); //Comment this to make it work
    match socket.read_to_end(&mut read) {
        // Comment this to make it work
        Ok(n) => {
            if n == 0 {
                // connection was closed
            }
            let msg = String::from_utf8(read.to_vec()).unwrap();
            println!("CLIENT: {} received from server.", msg);
        }
        Err(err) => {
            panic!(err);
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    if args.len() > 2 {
        let operation_mode = args[1].clone();
        let address = args[2].clone();

        if operation_mode == "server" {
            start_server(address);
        } else {
            let msg = args[3].clone();
            start_client(address, msg);
        }
    } else {
        println!("not enough parameters");
    }
}

要重现此问题,请运行如下服务器进程:rm /tmp/sock & RUST_BACKTRACE=1 cargo run server /tmp/sock以及之后的客户端进程,如下所示:cargo run client /tmp/sock hello_world

问题再现时的预期输出是服务器进程按预期打印其输出:SERVER: hello_world received from remote client.但客户端进程不打印任何内容,直到服务器进程被终止,此时它将打印其预期输出:{ {1}}

要确认此问题已本地化为CLIENT: hello_world received from server.方法,请取消注释标记为工作变体的行,并对标记为示例的行进行注释。

此代码有什么问题?我使用read_to_end错了吗?

0 个答案:

没有答案