#TCP Server in rust

49 messages Β· Page 1 of 1 (latest)

broken folio
#

Hi, i'm doing a TCP server in rust and i want to do a "feature".
the feature consists in: when i Ctrl + C, all the clients connected receives a "STOP" message.
but the compiler throw me an error:

  --> src\main.rs:46:17
   |
26 |       let mut users = Vec::<User>::new();
   |           --------- move occurs because `users` has type `Vec<User>`, which does not implement the `Copy` trait
27 |       let socket = TcpListener::bind("127.0.0.1:5050").unwrap();
28 |       let users_in_arc = Arc::new(Mutex::new(users));
   |                                              ----- value moved here
...
46 | /                 users.push(User {
47 | |                     name,
48 | |                     socket: stream.try_clone().unwrap()
49 | |                 });
   | |__________________^ value borrowed here after move

this is my code:

use ctrlc as signal;
use std::io::{Write, Read, Error};
use std::process::exit;
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;

#[allow(unused)]
struct User {
    name: String,
    socket: Arc<Mutex<TcpStream>>,
}

fn handle_connection(_stream: &mut TcpStream) {}

fn request_data(connection: &mut TcpStream) -> Result<String, Error> {
    connection.write_all(b"NICK").unwrap();
    let mut name= String::new();
    match connection.read_to_string(&mut name) {
        Ok(_) => Ok(name),
        Err(err) => Err(err)
    }
}

fn main() {

    let socket = TcpListener::bind("127.0.0.1:5050").unwrap();
    let users_in_arc = Arc::new(Mutex::new(Vec::<User>::new()));
    // Signal detection
    signal::set_handler(move || {
        println!("πŸ”ͺ Exiting...");
        let users_ref = users_in_arc.clone();
        let mut users = users_ref.lock().unwrap();
        users.iter_mut().for_each(|user| {
            let mut socket = user.socket.lock().unwrap();
            socket.write(b"STOP");
        });
        exit(1);
    }).expect("❌ Error setting Signal Handler");

    println!("πŸš€ Listening on: {}", socket.local_addr().unwrap());

    let users_in_arc_clone = users_in_arc.clone();
    thread::spawn(move || {
        // Accept connections in a loop
        for stream in socket.incoming() {
            if let Ok(mut stream) = stream {
                println!("⏳ Receiving connection... Awaiting Authentication.");
                if let Ok(name) = request_data(&mut stream) {
                    println!("βœ… Client {} authorized.", &name);
                    // Get a mutable reference to the Arc<Mutex<TcpStream>>
                    let users_ref = &users_in_arc_clone;
                    let mut users = users_ref.lock().unwrap();
                    // Push the new user to the vector
                    users.push(User {
                        name,
                        socket: Arc::new(Mutex::new(stream.try_clone().unwrap()))
                    });
                    handle_connection(&mut stream);
                } else {
                    println!("πŸ“‘ Connection canceled.");
                }
            }
        }
    });

    // for stream in socket.incoming() {
    //     if let Ok(mut stream) = stream {
    //         println!("⏳ Receiving connection... Awaiting Authentication.");
    //         if let Ok(name) = request_data(&mut stream) {
    //             println!("βœ… Client {} authorized.", &name);
    //             let users_ref = users_in_arc.clone();
    //             let mut users = users_ref.lock().unwrap();
    //             // Push the new user to the vector
    //             users.push(User {
    //                 name,
    //                 socket: Arc::new(Mutex::new(stream.try_clone().unwrap()))
    //             });
    //             handle_connection(&mut stream);
    //         } else {
    //             println!("πŸ“‘ Connection canceled.");
    //         }
    //     }
    // }
}

how can i share the vector of users to push new connections and send "simultaneously" the "STOP" message?

chat gpt didn't help much :(

balmy granite
#

I get a different error than the one you said:

error[E0382]: borrow of moved value: `users_in_arc`
  --> main.rs:43:30
   |
28 |     let users_in_arc = Arc::new(Mutex::new(Vec::<User>::new()));
   |         ------------ move occurs because `users_in_arc` has type `Arc<Mutex<Vec<User>>>`, which does not implement the `Copy` trait
29 |     // Signal detection
30 |     signal::set_handler(move || {
   |                         ------- value moved into closure here
31 |         println!("πŸ”ͺ Exiting...");
32 |         let users_ref = users_in_arc.clone();
   |                         ------------ variable moved due to use in closure
...
43 |     let users_in_arc_clone = users_in_arc.clone();
   |                              ^^^^^^^^^^^^^^^^^^^^ value borrowed here after move

If you still get your original error:
You probably want to "shadow" users with users_in_arc, since users doesn't exist anymore after making users_in_arc. I.e. rename users_in_arc to just users.

If you get the error I got: You should .clone() the Arc before the closure, otherwise you are moving it into the closure then cloning it, i.e.

signal::set_handler({
    let users_in_arc = users_in_arc.clone();
    move || {
        println!("πŸ”ͺ Exiting...");
        let users_ref = users_in_arc.clone();
        let mut users = users_ref.lock().unwrap();
        users.iter_mut().for_each(|user| {
            let mut socket = user.socket.lock().unwrap();
            socket.write(b"STOP");
        });
        exit(1);
    }
}).expect("❌ Error setting Signal Handler");
broken folio
#

Sorry for not responding, I'll try your solution in a while and I'll let you know! Thank you very much in advance

broken folio
#

the second solution works for me, but when i run the program with cargo run --release -q the program stops inmediatly without console errors

#
use ctrlc as signal;
use std::io::{Write, Read, Error};
use std::process::exit;
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;

#[allow(unused)]
struct User {
    name: String,
    socket: Arc<Mutex<TcpStream>>,
}

fn handle_connection(_stream: &mut TcpStream) {}

fn request_data(connection: &mut TcpStream) -> Result<String, Error> {
    connection.write_all(b"NICK").unwrap();
    let mut name= String::new();
    match connection.read_to_string(&mut name) {
        Ok(_) => Ok(name),
        Err(err) => Err(err)
    }
}

fn main() {

    let socket = TcpListener::bind("127.0.0.1:5050").unwrap();
    let users = Arc::new(Mutex::new(Vec::<User>::new()));
    // Signal detection
    signal::set_handler({
        let users = users.clone();
        move || {
        println!("πŸ”ͺ Exiting...");
        let mut users = users.lock().unwrap();
        users.iter_mut().for_each(|user| {
            let mut socket = user.socket.lock().unwrap();
            socket.write(b"STOP").unwrap();
        });
        exit(1);
    }}).expect("❌ Error setting Signal Handler");

    println!("πŸš€ Listening on: {}", socket.local_addr().unwrap());

    let users_arc = users.clone();
    thread::spawn(move || {
        // Accept connections in a loop
        for stream in socket.incoming() {
            if let Ok(mut stream) = stream {
                println!("⏳ Receiving connection... Awaiting Authentication.");
                if let Ok(name) = request_data(&mut stream) {
                    println!("βœ… Client {} authorized.", &name);
                    // Get a mutable reference to the Arc<Mutex<TcpStream>>
                    let users_ref = &users_arc;
                    let mut users = users_ref.lock().unwrap();
                    // Push the new user to the vector
                    users.push(User {
                        name,
                        socket: Arc::new(Mutex::new(stream.try_clone().unwrap()))
                    });
                    handle_connection(&mut stream);
                } else {
                    println!("πŸ“‘ Connection canceled.");
                }
            }
        }
    });
}
#

that's the code

#

sorry if i make mistakes

#

I'm not familiar with sockets at all.

balmy granite
#

When the main thread exits, all other threads are killed, so you beed to .join() the JoinHandle returned from thread::spawn to keep main running as long as the server thread is running. Alternately just run the code on the main thread.

broken folio
#

oh like

my_thread = thread::spawn()
my_thread.join()

?

#

works!

#

i coded a client in py to work with both lenguages but when i connect with the server, the message "client {} autorized" doesn't show, Could there be something wrong with my server code or could it be a bug in my client code?

balmy granite
#

Does it not print anything, or does it print "connection canceled"?

broken folio
#

does not print the message directly

#

should i show the client side code?

#

ok, i debugged and i found that's an issue with the client side

broken folio
#

i dont know

#

maybe is this function ```rs
fn request_data(connection: &mut TcpStream) -> Result<String, Error> {
connection.write_all(b"NICK").unwrap();
let mut name = String::new();
match connection.read_to_string(&mut name) {
Ok(_) => Ok(name),
Err(err) => Err(err),
}
}

#

i dont know how to explain

#

but is weird

#

Apparently the function stays in a loop waiting for the user to disconnect, because no matter how much the message receives it, if I do ctrl c the program doesn't detect that I requested that value and it tells me "πŸ“‘ Connection cancelled."

#

thats make sense...

#

i advance a little more...

#

that's my actual function ```rs
fn request_data(connection: &mut TcpStream) -> Result<String, Error> {
connection.write_all(b"NICK").unwrap();
let mut name = [0, 255];
match connection.read(&mut name) {
Ok(_) => Ok(String::from_utf8(name.to_vec()).unwrap()),
Err(err) => Err(err),
}
}

#

should i change anything?

#

After doing some research, I found this post: https://stackoverflow.com/questions/44015638/simple-rust-tcp-server-and-client-do-not-receive-messages-and-never-terminates and I was able to find the solution to the problem.

#
fn request_data(connection: &mut TcpStream) -> Result<String, Error> {
    connection.write_all(b"NICK").unwrap();
    let mut reader = BufReader::new(connection);
    let mut response = String::new();
    match reader.read_line(&mut response) {
        Ok(_) => Ok(response),
        Err(err) => Err(err),
    }
}
#

that's my actual function

balmy granite
broken folio
#

and how can i use try_clone() in this case?

balmy granite
#
let mut writer = stream;
let mut reader = BufReader::new(writer.try_clone().unwrap());
#

Then only write through writer, and only read through reader

broken folio
#

good idea, let me try

broken folio
#
fn request_data(writer:&mut TcpStream, reader:&mut BufReader<TcpStream>) -> Result<String, Error> {
    writer.write_all(b"NICK").unwrap();
    let mut response = String::new();
    match reader.read_line(&mut response) {
        Ok(_) => Ok(response.replace("\n", "")),
        Err(err) => Err(err),
    }
}

for stream in socket.incoming() {
        if let Ok(mut stream) = stream {
            println!("⏳ Receiving connection... Awaiting Authentication.");
            let mut reader = BufReader::new(stream.try_clone().unwrap());
            if let Ok(name) = request_data(&mut stream, &mut reader) {
                println!("βœ… Client {} authorized.", &name);
                let users_ref = &users_arc;
                let mut users = users_ref.lock().unwrap();
                users.push(User {
                    name,
                    socket: Arc::new(Mutex::new(stream.try_clone().unwrap())),
                });
                handle_messages(&mut stream, &users_arc)
            } else {
                println!("πŸ“‘ Connection canceled.");
            }
        }
    }
#

works fine

#

but

#

when i press Ctrl c

#

the program freeze in the "exiting"

#

and never end in the exit(1)

#
signal::set_handler({
        let users = users.clone();
        move || {
            println!("πŸ”ͺ Exiting...");
            let mut users = users.lock().unwrap();
            users.iter_mut().for_each(|user| {
                let mut socket = user.socket.lock().unwrap();
                socket.write(b"STOP").unwrap();
            });
            exit(1);
        }
    })
    .expect("❌ Error setting Signal Handler");
#

maybe the users.iter_mut is not work correctly

#

i edited the function to this:

signal::set_handler({
        let users = users.clone();
        move || {
            println!("πŸ”ͺ Exiting...");
            let mut users = users.lock().unwrap();
            users.iter_mut().for_each(|user| {
                print!("{user:#?}");
                // let mut socket = user.socket.lock().unwrap();
                // socket.write(b"STOP").unwrap();
            });
            exit(1);
        }
    })
    .expect("❌ Error setting Signal Handler");

but its the same thing

balmy granite
#

If you are using a mutex, then .lock() will block the thread until anything else using it stops. Generally a ctrlc handler should just set a "flag" (a shared AtomicBool) to tell the main program that it should exit, but that may be hard in combination with .incoming()

broken folio
#

oh

broken folio
#

ok, thanks for help me man