3
\$\begingroup\$

I have created client and server which can read and write from both side in client as well server. So what more improvement can be done so the code should be performant and better?

Following are three files, main.rs, client.rs, server.rs. (cargo new tcp-server).

src/main.rs

mod client;
mod server;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    match args.get(1).map(|s| s.as_str()) {
        Some("server") => {
            println!("Starting server...");
            server::start();
        }
        Some("client") => {
            println!("Starting client...");
            client::start();
        }
        _ => {
            println!("Usage: tcp-server [server|client]");
        }
    }
}

src/client.rs

use std::io::{self, Read, Write};
use std::net::TcpStream;
use std::thread;

fn send_to_server(mut stream: TcpStream) {
    let mut buffer: String = String::new();

    loop {
        println!("Enter message: ");

        io::stdin()
            .read_line(&mut buffer)
            .expect("Failed to read from stdin");

        match stream.write_all(buffer.as_bytes()) {
            Ok(_) => {
                buffer.clear();
            }
            Err(e) => {
                println!("Failed to write to server: {}", e);
                break;
            }
        }
    }
}

fn recv_from_server(mut stream: TcpStream) {
    let mut buffer = [0; 512];

    loop {
        match stream.read(&mut buffer) {
            Ok(n) => {
                if n == 0 {
                    println!("Server closed connection");
                    break;
                }

                println!("Received: {}", String::from_utf8_lossy(&buffer[..n]));

                io::stdout()
                    .write_all(&buffer[..n])
                    .expect("Failed to write to stdout");
            }
            Err(e) => {
                println!("Failed to read from server: {}", e);
                break;
            }
        }
    }
}

pub(crate) fn start() {
    let stream = TcpStream::connect("127.0.0.1:6500").expect("Could not connect to server");

    let send_handle = {
        let stream_clone = stream
            .try_clone()
            .expect("Failed to clone stream for sending");
        thread::spawn(move || {
            send_to_server(stream_clone);
        })
    };

    let recv_handle = thread::spawn(move || {
        recv_from_server(stream);
    });

    send_handle.join().expect("Failed to join send thread");
    recv_handle.join().expect("Failed to join receive thread");
}

src/server.rs

use std::io::{self, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;

fn recv_from_client(mut conn: TcpStream) {
    let mut buffer = [0; 512];
    loop {
        match conn.read(&mut buffer) {
            Ok(n) => {
                if n == 0 {
                    println!("Client closed connection");
                    break;
                }

                println!("Received: {}", String::from_utf8_lossy(&buffer[..n]));

                io::stdout()
                    .write_all(&buffer[..n])
                    .expect("Failed to write to stdout");
            }
            Err(e) => {
                println!("Failed to read from client: {}", e);
                break;
            }
        }
    }
}

fn send_to_client(mut conn: TcpStream) {
    let mut buffer: String = String::new();

    loop {
        println!("Enter message: ");

        io::stdin()
            .read_line(&mut buffer)
            .expect("Failed to read from stdin");

        match conn.write_all(buffer.as_bytes()) {
            Ok(_) => {
                buffer.clear();
            }
            Err(e) => {
                println!("Failed to write to client: {}", e);
                break;
            }
        }
    }
}

pub(crate) fn start() {
    let listener = TcpListener::bind("127.0.0.1:6500").expect("Could not bind to address");

    loop {
        match listener.accept() {
            Ok((conn, _)) => {
                let conn_clone = conn.try_clone().expect("Could not clone connection");

                println!("Client connected");

                thread::spawn(move || {
                    recv_from_client(conn);
                });

                thread::spawn(move || {
                    send_to_client(conn_clone);
                });
            }
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                // do nothing
            }
            Err(e) => {
                println!("Failed to accept connection: {}", e);
                break;
            }
        }
    }
}
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.