我想用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
如何从客户端读取这些消息?
答案 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
}
}