unistd :: read()始终返回0

时间:2019-10-12 02:47:37

标签: rust ipc unix-socket

我想用unix域套接字实现服务器/客户端程序。该程序 1.启动时,在抽象名称空间中创建一个套接字和一个Unix地址 2.尝试将套接字绑定到该地址,如果绑定失败并返回EADDRINUSE,它将创建一个客户端,否则,如果绑定成功,则创建一个服务器。服务器永远在后台运行。 3.建立UDS IPC。

但是在我的server函数中,read()的结果似乎总是返回0;因此根本不检索任何消息。

执行: 航站楼A:

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/testrs`
Primary instance detected, launching server.
Listening...
Ending connection
Ending connection
Ending connection
^C

B终端:(在运行命令之后)

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/testrs`
Secondary instance detected, launching client.
Message sent.
Exiting...
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/testrs`
Secondary instance detected, launching client.
Message sent.
Exiting...
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/testrs`
Secondary instance detected, launching client.
Message sent.
Exiting...

其他:

// Reference implementation: http://osr507doc.sco.com/en/netguide/dusockT.code_samples.html
use {
    nix::{
        errno::Errno::EADDRINUSE,
        sys::socket::{
            accept, bind, connect, listen, socket, AddressFamily, SockAddr, SockFlag, SockType,
            UnixAddr,
        },
        unistd::{close, read, write},
        Error::Sys,
    },
    std::{error::Error, os::unix::io::RawFd},
};

macro_rules! Expected {
    () => {
        Result<(), Box<dyn Error>>
    };
    // ($t:ty) => {
    //     Result<$t, Box<dyn Error>>
    // }
}

static SOCK_ADDR: &'static str = "com.localserver.myapp.sock";
const MESSAGE_CAPACITY: usize = 64; // can't create static size array

fn heavy_task(arg: &str) {
    println!("Received message: {}", arg);
    std::thread::sleep(std::time::Duration::from_secs(5));
}

服务器:

fn server(sock: RawFd) -> Expected!() {
    listen(sock, 0)?;
    println!("Listening...");
    loop {
        match accept(sock) {
            Ok(msgsock) => loop {
                //let mut buf = [0u8; MESSAGE_CAPACITY];
                let mut buf = String::with_capacity(MESSAGE_CAPACITY);
                unsafe {
                    let rval = read(msgsock, buf.as_bytes_mut())?;
                    if rval == 0 {
                        println!("Ending connection");
                        break;
                    } else {
                        println!("Message recived, emulating heavy task.");
                        // TODO ignore all the incoming messages 
                        heavy_task(&buf);
                        // TODO re-enable accepting new messages
                    }
                }
                close(msgsock)?;
            },
            // EBADF here
            Err(e) => {
                close(sock)?;
                panic!("Error accepting socket {:?}", e)
            }
        }
    }
    // Ok(()) // unreachable
}

客户:

fn client(sock: RawFd, addr: &SockAddr) -> Expected!() {
    match connect(sock, addr) {
        Ok(_) => {
            let mut buf = String::from("Message from client");
            unsafe {
                write(sock, buf.as_bytes_mut())?;
            }
            close(sock)?;
            Ok(())
        }
        Err(e) => {
            close(sock)?;
            panic!("Error connecting to socket: {}", e);
        }
    }
}

主要:

fn main() -> Expected!() {
    let sock: RawFd = socket(
        AddressFamily::Unix,
        SockType::Stream,
        SockFlag::empty(),
        None, // Protocol
    )?;

    let addr = SockAddr::Unix(UnixAddr::new_abstract(SOCK_ADDR.as_bytes())?);

    // Unlink before bind
    // However Abstract domain sockets (which we are using) are automatically
    // cleaned up by the kernel so no need to unlink

    match bind(sock, &addr) {
        Err(e) => match e {
            Sys(EADDRINUSE) => {
                println!("Secondary instance detected, launching client.");
                match client(sock, &addr) {
                    Ok(_) => println!("Message sent."),
                    Err(_) => println!("Message sending failed."),
                }
                println!("Exiting...");
            }
            _ => {
                panic!("Socket binding failed due to: {:?}", e);
            }
        },
        Ok(_) => {
            println!("Primary instance detected, launching server.");
            server(sock)?;
        }
    }

    Ok(())
}

我尝试在服务器上关闭连接:

if rval == 0 {
    // println!("Ending connection");
    // break;
} 

在这种情况下,服务器无法说出EBADF 如何从客户端读取这些消息?

1 个答案:

答案 0 :(得分:0)

在看来,由于String的工作原理,发送buf无效。要解决此问题,您需要将&mut[u8]传递给read函数:

Ok(msgsock) => loop {
                //let mut buf = [0u8; MESSAGE_CAPACITY];
                let mut buf = [0u8; MESSAGE_CAPACITY];
                    let rval = read(msgsock, &mut buf[..])?;
                    if rval == 0 {
                        println!("Ending connection");
                        break;
                    } else {
                        println!("Message recived, emulating heavy task.");
                        // TODO ignore all the incoming messages 
                        heavy_task(std::str::from_utf8(&buf)?);
                        // TODO re-enable accepting new messages
                    }
}