unistd :: read () всегда возвращает 0 - PullRequest
0 голосов
/ 12 октября 2019

Я хочу реализовать серверную / клиентскую программу с сокетом домена 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 голосов
/ 12 октября 2019

Появляется, что отправка этого buf не будет работать из-за того, как работает String. Чтобы это исправить, вам нужно передать &mut[u8] в функцию чтения:

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
                    }
}
...