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