I am trying to create TCP/IP server and client, it should be multi-thread, multi-client and bidirectional communication.
So that any number of client connect and communicate, after connection server can send data or recieve data similarly client can send or receive data.
I am not asking for chat server because it broadcast each message to each client instead I want to send or receive message to connected client. Also if both client and server connected and server recieved request from client it sends the data, but it may request data message also in which client will send some data.
I have tried to implement this, below are client.rs, server.rs and main.rs file.
client.rs
// client.rs
use std::io::{Read, Write};
use std::net::TcpStream;
use std::thread;
pub fn run() {
let mut stream = TcpStream::connect("127.0.0.1:8080").expect("Failed to connect to server");
let mut cloned_stream = stream.try_clone().expect("Failed to clone stream");
thread::spawn(move || {
let mut buffer = [0; 1024];
loop {
let bytes_read = cloned_stream
.read(&mut buffer)
.expect("Failed to read from server");
if bytes_read == 0 {
println!("Server disconnected");
return;
}
println!(
"Received from server: {}",
String::from_utf8_lossy(&buffer[..bytes_read])
);
}
});
loop {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("Failed to read input");
stream
.write_all(input.as_bytes())
.expect("Failed to write to server");
}
}
server.rs
// server.rs
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;
pub fn run() {
let listener = TcpListener::bind("127.0.0.1:8080").expect("Failed to bind");
println!("Server listening on port 8080...");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
thread::spawn(move || {
handle_client(stream);
});
}
Err(e) => {
println!("Failed to accept connection: {:?}", e);
}
}
}
}
fn handle_client(mut stream: TcpStream) {
println!("Client connected: {:?}", stream.peer_addr().unwrap());
let mut buffer = [0; 1024];
loop {
match stream.read(&mut buffer) {
Ok(bytes_read) => {
if bytes_read == 0 {
println!("Client disconnected: {:?}", stream.peer_addr().unwrap());
return;
}
println!(
"Received: {}",
String::from_utf8_lossy(&buffer[..bytes_read])
);
// Echo back to the client
stream.write_all(&buffer[..bytes_read]).unwrap();
}
Err(_) => {
println!(
"Error reading from client: {:?}",
stream.peer_addr().unwrap()
);
return;
}
}
}
}
main.rs
use std::env;
mod client;
mod server;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
println!("Usage: {} [server|client]", args[0]);
return;
}
let mode = &args[1];
match mode.as_str() {
"server" => {
println!("Starting server...");
server::run();
}
"client" => {
println!("Starting client...");
client::run();
}
_ => {
println!("Invalid mode. Please specify either 'server' or 'client'.");
}
}
}