Доменные сокеты Unix в Rust

Я написал пример кода, в котором пытаюсь использовать сокеты домена unix для связи между двумя потоками, но не могу этого сделать. После подключения клиента к серверу клиент не получает сообщение, отправленное с сервера, в данном случае Hello, I'm server.

use std::os::unix::net::{UnixListener, UnixStream};
use std::io::prelude::*;

fn server() {
    let listener = match UnixListener::bind("/tmp/rst.sock") {
        Ok(listener) => listener,
        Err(e) => {
            eprintln!("Couldn't bind: {e:?}");
            return;            
        }
    };

    match listener.accept() {
        Ok((mut socket, addr)) => {
            println!("Got a client: {:?} - {:?}", socket, addr);
            
            match socket.write_all(b"Hello, I'm server") {
                Ok(()) => println!("server sent"),
                Err(e) => {
                    eprintln!("server failed while writing {e:?}");
                    return;
                },
            }
            
            let mut response = String::new();
            match socket.read_to_string(&mut response) {
                Ok(length) => println!("server received {} bytes {}", length, response),
                Err(e) => {
                    eprintln!("server Couldn't read: {e:?}");
                    return;
                },
            }
        },
        Err(e) => println!("accept function failed: {:?}", e),
    }
}

fn client() {
    let mut socket = match UnixStream::connect("/tmp/rst.sock") {
        Ok(sock) => sock,
        Err(e) => {
            eprintln!("Couldn't connect: {e:?}");
            return;
        },
    };
    println!("client connected");
    
    let mut response = String::new();
    match socket.read_to_string(&mut response) {
        Ok(length) => println!("client received {} bytes {}", length, response),
        Err(e) => {
            eprintln!("client couldn't read: {e:?}");
            return;
        },
    }
    
    match socket.write_all(b"Hello, I'm client") {
        Ok(()) => println!("client sent"),
        Err(e) => {
            eprintln!("client couldn't send: {e:?}");
            return;
        },
    }
}

fn main() {
    let server_handle = std::thread::spawn(|| {
        server();
    });
    
    std::thread::sleep(std::time::Duration::from_secs(1));
    
    let client_handle = std::thread::spawn(|| {
        client();
    });
    
    let _ = server_handle.join();
    let _ = client_handle.join();
}

Пожалуйста, отредактируйте свое сообщение, чтобы уточнить точный вывод опубликованного вами кода и ожидаемый код. «Не произошло» не дает много информации о том, с чем вы на самом деле столкнулись.

mousetail 05.05.2024 17:24

Метод read_to_string может ожидать закрытия сокета перед возвратом. Возможно, вы захотите использовать некоторые из более примитивных функций, чтобы иметь возможность читать фиксированное количество байтов вместо того, чтобы ждать окончания соединения.

mousetail 05.05.2024 17:29

@mousetail У меня есть сомнения. В этом случае какой будет type сокета, который будет создан? Я имею в виду SOCK_STREAM или SOCK_DGRAM или SOCK_SEQPACKET, как в C. И как мне указать сокет type?

Harry 05.05.2024 17:33

@Гарри Это SOCK_STREAM.

user4815162342 05.05.2024 17:35

Так же, как и в случае стилистической организации кода, вам, вероятно, следует разделить server и client на отдельные функции, которые возвращают Result, и выполнять обработку ошибок в паре функций верхнего уровня, которые ничего не делают, а делегируют этим функциям и обрабатывают ошибки.

Jared Smith 06.05.2024 14:49
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
5
128
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я сделал это с помощью uds crate, который предоставляет SEQPACKET типы сокетов.

use uds::{UnixSeqpacketListener, UnixSeqpacketConn};

fn server() {
    let listener = match UnixSeqpacketListener::bind("/tmp/rst.sock") {
        Ok(listener) => listener,
        Err(e) => {
            eprintln!("Couldn't bind: {e:?}");
            return;            
        }
    };

    match listener.accept_unix_addr() {
        Ok((socket, addr)) => {
            println!("Got a client: {:?} - {:?}", socket, addr);
            
            match socket.send(b"Hello, I'm server") {
                Ok(s) => println!("server sent {s} bytes"),
                Err(e) => {
                    eprintln!("server failed while writing {e:?}");
                    return;
                },
            }
            
            let mut buff = [0u8; 1024];
            match socket.recv(&mut buff) {
                Ok(length) => println!("server received {} bytes {:?}", length, &buff[..length]),
                Err(e) => {
                    eprintln!("server Couldn't read: {e:?}");
                    return;
                },
            }
        },
        Err(e) => println!("accept function failed: {:?}", e),
    }
}

fn client() {
    let socket = match UnixSeqpacketConn::connect("/tmp/rst.sock") {
        Ok(sock) => sock,
        Err(e) => {
            eprintln!("Couldn't connect: {e:?}");
            return;
        },
    };
    println!("client connected");
    
    let mut buff = [0u8; 1024];
    match socket.recv(&mut buff) {
        Ok(length) => println!("client received {} bytes {:?}", length, &buff[..length]),
        Err(e) => {
            eprintln!("client couldn't read: {e:?}");
            return;
        },
    }
    
    match socket.send(b"Hello, I'm client") {
        Ok(s) => println!("client sent {s} bytes"),
        Err(e) => {
            eprintln!("client couldn't send: {e:?}");
            return;
        },
    }
}

fn main() {
    let server_handle = std::thread::spawn(|| {
        server();
    });
    
    std::thread::sleep(std::time::Duration::from_secs(1));
    
    let client_handle = std::thread::spawn(|| {
        client();
    });
    
    let _ = server_handle.join();
    let _ = client_handle.join();
}

Другие вопросы по теме