I am trying to build minitalk project from 42 school using Rust instead of C. This is a communication program between a client and a server. Both are process. To achieve this I am only allowed to use UNIX Signals SIGUSR1 and SIGUSR2. While I got help to achieve this, I would appreciate an external point of view for the below code.
server.rs
use signal_hook::{iterator::Signals, consts::{SIGUSR1, SIGUSR2}};
use std::error::Error;
use std::sync::{Arc, Mutex};
use std::time::{Instant, Duration};
use std::thread;
fn main() -> Result<(), Box<dyn Error>> {
let pid = std::process::id();
println!("Server PID: {}", pid);
let message = Arc::new(Mutex::new(Vec::new()));
let last_received = Arc::new(Mutex::new(Instant::now()));
let mut signals = Signals::new(&[SIGUSR1, SIGUSR2])?;
let message_clone = Arc::clone(&message);
let last_received_clone = Arc::clone(&last_received);
thread::spawn(move || {
let mut byte = 0;
let mut bit_count = 0;
for sig in signals.forever() {
let mut last_received = last_received_clone.lock().unwrap();
*last_received = Instant::now();
drop(last_received);
let mut message = message_clone.lock().unwrap();
match sig {
SIGUSR1 => byte |= 1 << bit_count,
SIGUSR2 => (),
_ => unreachable!(),
}
bit_count += 1;
if bit_count == 8 {
message.push(byte);
byte = 0;
bit_count = 0;
}
}
});
loop {
thread::sleep(Duration::from_millis(1));
let last_received = last_received.lock().unwrap();
if last_received.elapsed() >= Duration::from_millis(50) {
let mut message = message.lock().unwrap();
if !message.is_empty() {
let message_str = String::from_utf8_lossy(&message);
println!("{}", message_str);
message.clear();
}
}
}
}
client.rs
use std::process::Command;
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let pid = &args[1];
let message = &args[2];
for byte in message.bytes() {
for i in 0..8 {
let bit = (byte >> i) & 1;
let signal = if bit == 1 { "SIGUSR1" } else { "SIGUSR2" };
Command::new("kill")
.arg(format!("-{}", signal))
.arg(pid)
.output()
.expect("Failed to send signal");
}
}
}
Cargo.toml
[package]
name = "minitalk"
version = "0.1.0"
edition = "2021"
[dependencies]
nix = "0.27.1"
signal-hook = "0.3.17"
libc = "0.2"
[[bin]]
name = "server"
path = "./src/server.rs"
[[bin]]
name = "client"
path = "./src/client.rs"
Execution: Open two terminal inside src directory (one to execute the server, one for client).
1st terminal:
cargo run --bin server
Server PID: "{x}"
2nd terminal:
cargo run --bin client server_pid hello
hello will print on the stdout of server bin.
While this work as expected, I would like to have your opinion on this program as this is in Rust and not C. Thanks
server.rs
andclient.rs
intosrc/bin
you don't need the sections in yourCargo.toml
because you conform to the standard project layout \$\endgroup\$