unix 两个子进程之间发送消息 rust nix

xjreopfe  于 2022-11-04  发布在  Unix
关注(0)|答案(2)|浏览(168)

我正在尝试实现一个练习与子进程和管道生 rust 。练习包括在子进程2发送消息到子进程1,我在c1中收到的消息,我必须返回到c2,我必须这样做10次每2秒。我有一个代码,可能会这样做,但当我想运行它,它仍然等待,我不能看到的消息。
这是我的代码:

use nix::sys::wait::wait;
use nix::unistd::ForkResult::{Child, Parent};
use nix::unistd::fork;
use std::io::prelude::*;
use std::time::Duration;

fn main() {
    let (mut reader, mut writer) = os_pipe::pipe().unwrap();
    let (mut reader_2, mut writer_2) = os_pipe::pipe().unwrap();
    let pid = fork();

    match pid.expect("Error during creating child") {
        Parent { child } => {
            drop(reader);
            drop(writer_2);
            let pid_2 = fork();
            match pid_2.expect("Error creating child 2") {
                Parent { child } => {}
                Child => {
                    for _ in 1..10 {
                        writer.write("C1".as_bytes()).unwrap();
                        let mut data = String::new();
                        reader_2.read_to_string(&mut data).unwrap();
                        println!("Data from C1, {}", data);
                        std::thread::sleep(Duration::from_millis(2000));
                    }
                }
            }
        }

        Child => {
            drop(writer);
            drop(reader_2);
            for _ in 1..10 {
                let mut data = String::new();
                reader.read_to_string(&mut data).unwrap();
                println!("Data from C2, {}", data);
                writer_2.write(data.to_string().as_bytes()).unwrap();
            }
        }
    }
    wait().unwrap();
}

谢谢!!!

axzmvihb

axzmvihb1#

代码等待的问题来自于使用read_to_string,它的文档说(我强调的是):
读取此源中的所有字节,直到EOF,并将它们附加到buf
第一个子进程在管道中发送一些数据,但并不关闭它。第二个子进程接收数据,但它想要 * 所有 * 数据,因此它只是等待另一端发送。它只有在收到EOF时才继续,但EOF永远不会到来,所以你有死锁。
要解决这个问题,您需要在两个通信进程之间定义某种协议,以便每一方都可以知道对方何时完成了它的消息。
在这种情况下,协议可以简单地是“在每条消息后发送一个换行符”,这将使您可以使用read_line轻松地实现它。
首先,您需要使用BufReader

use std::io::BufReader;

然后将两个读卡器封装在BufReader中:

let mut reader = BufReader::new(reader);
let mut reader_2 = BufReader::new(reader_2);

现在,您可以将对read_to_string的呼叫与对read_line的呼叫交换:

reader.read_line(&mut data).unwrap();

发送数据时,请确保添加换行符,否则将再次死锁:

writer.write("C1\n".as_bytes()).unwrap();

现在,当接收方收到一条消息时,它会看到有一个换行符,并且会继续,而不等待更多永远不会到达的字节。
请注意,read_line返回的行 * 包括换行符 *,因此您可能需要删除它。

omtl5h9j

omtl5h9j2#

您可以将数据更改为大小为2的u8切片,并使用read_exact代替read_to_string

Parent { child } => {
            drop(reader);
            drop(writer_2);
            let pid_2 = unsafe{ fork() };
            match pid_2.expect("Error creating child 2") {
                Parent { child } => {}
                Child => {
                    let mut data: [u8;2] = [0;2];
                    for _ in 1..10 {
                        writer.write("C1".as_bytes()).unwrap();
                        reader_2.read_exact(&mut data).unwrap();
                        println!("Data from C1, {}", std::str::from_utf8(&data).unwrap());
                        std::thread::sleep(Duration::from_millis(2000));
                    }
                }
            }
        }

        Child => {
            drop(writer);
            drop(reader_2);
            let mut data: [u8;2] = [0;2];
            for _ in 1..10 {
                reader.read_exact(&mut data).unwrap();
                println!("Data from C2, {}", std::str::from_utf8(&data).unwrap());
                writer_2.write(&data).unwrap();
            }
        }
    }

相关问题