In my application I'm making use of unix domain sockets to perform local communication and I've used the uds
crate for that. I need to shutdown the sockets(both listeners and clients, selectively), but with my current code design I'm not able to. Can somebody help me here.
main.rs
mod uds_listener;
mod uds_client;
use std::thread::JoinHandle;
use uds_listener::UdsListener;
use uds_client::UdsClient;
fn main() {
let mut uds_listeners_thread_join_handle_list: Vec<JoinHandle<()>> = Vec::new();
for i in 0..256 {
let uds_listnener = UdsListener::new(&format!("{}{}{}", "/tmp/sock_", i.to_string(), ".sock"));
let uds_listener_jh = uds_listnener.spawn_thread();
uds_listeners_thread_join_handle_list.push(uds_listener_jh);
}
let mut uds_clients_thread_join_handle_list: Vec<JoinHandle<()>> = Vec::new();
for i in 0..256 {
let uds_client = UdsClient::new(&format!("{}{}{}", "/tmp/sock_", i.to_string(), ".sock"));
let uds_client_jh = uds_client.spawn_thread();
uds_clients_thread_join_handle_list.push(uds_client_jh);
}
// but how to request threads blocked on data reception to terminate
// one way is to shutdown the socket(both read and write, which will result in data reception of length 0), but that's not possible with my current code design as socket is owned by thread
println!("waiting for listener threads to join");
while let Some(ljh) = uds_listeners_thread_join_handle_list.pop() {
let _ = ljh.join();
}
println!("waiting for client threads to join");
while let Some(cjh) = uds_clients_thread_join_handle_list.pop() {
let _ = cjh.join();
}
}
uds_listener.rs
use std::thread;
use uds::UnixSeqpacketListener;
pub struct UdsListener {
listener: UnixSeqpacketListener,
}
impl UdsListener {
pub fn new(sock_name: &str) -> Self {
Self {
listener: Self::bind(sock_name),
}
}
fn bind(sock_name: &str) -> UnixSeqpacketListener {
match UnixSeqpacketListener::bind(sock_name) {
Ok(listener) => listener,
Err(e) => panic!("uds listener bind failed for {sock_name}: {e:?}"),
}
}
pub fn spawn_thread(mut self) -> thread::JoinHandle<()> {
thread::spawn(move || {
self.run();
})
}
fn run(&mut self) {
if let Ok((socket, _)) = self.listener.accept_unix_addr() {
let mut buff = [0u8; 8192];
loop {
match socket.recv(&mut buff) {
Ok(length) => {
if length == 0 {
break;
}
},
Err(e) => panic!("uds listener read failed: {e:?}"),
}
}
}
}
}
uds_client.rs
use std::{time, thread};
use uds::UnixSeqpacketConn;
pub struct UdsClient {
socket: UnixSeqpacketConn,
}
impl UdsClient {
pub fn new(sock_name: &str) -> Self {
Self {
socket: Self::connect(sock_name),
}
}
fn connect(sock_name: &str) -> UnixSeqpacketConn {
loop {
match UnixSeqpacketConn::connect(sock_name) {
Ok(socket) => return socket,
Err(_) => thread::sleep(time::Duration::from_secs(1)),
}
}
}
pub fn spawn_thread(mut self) -> thread::JoinHandle<()> {
thread::spawn(move || {
self.run();
})
}
fn run(&mut self) {
let mut buff = [0u8; 8192];
loop {
match self.socket.recv(&mut buff) {
Ok(length) => {
if length == 0 {
break;
}
},
Err(e) => panic!("uds client read failed: {e:?}"),
}
}
}
}
cargo.toml
[package]
name = "udss"
version = "0.1.0"
edition = "2021"
[dependencies]
uds = "0.4.2"