1

I'm trying to handle TcpStream using threads in a Rust program (a tcp server). I want to keep tracks of currents clients connections in a HashMap using an Arc<Mutex<HashMap>>.

When a thread is finished, to remove the connection from the HashMap, I thought about using an uuid, passed to the function used to handle the stream. Like this it could be send inside a mpsc channel to the main thread and then remove the connection from the HashMap.

The code from the main thread :

let clients_streams = Arc::new(Mutex::new(HashMap::new()));

// Server thread. Create channel
let (server_sender, server_receiver) = mpsc::channel();

loop {
    for stream in server_socket.incoming() {
        let clients_streams = Arc::clone(&clients_streams);
        let server_sender = server_sender.clone();
        let mut cs = clients_streams.lock().unwrap();

        match stream {
            Ok(stream) => {
                let mut cs = clients_streams.lock().unwrap();
                let uuid = Uuid::new_v4().to_string();
                cs.insert(uuid.clone(), stream.try_clone());

                thread::spawn(move || {
                    handle_client(stream, server_sender.clone(), uuid.clone());
                })
            }
            Err(err) => thread::spawn(move || {
                println!("Connection failed : {}", err);
            }),
        };
    }

The handle_client function :

fn handle_client<'a>(stream: TcpStream, sender: mpsc::Sender<&'a [u8]>, uuid: String) {
    let mut reader = BufReader::new(&stream);
    let mut writer = BufWriter::new(&stream);

    writer.write(b"Hello\n").unwrap();
    writer.flush().unwrap();

    // Read from client
    loop {
        let mut resp = Vec::new();
        let read_bytes = reader.read_until(b'\n', &mut resp);
        match read_bytes {
            Ok(read_bytes) => {
                if read_bytes == 0 {
                    let msg = format!("end of {}", uuid);
                    println!("connection closed by remote");
                    sender.send(msg.as_bytes()).unwrap();
                    break;
                };
            }
            Err(err) => match err.kind() {
                io::ErrorKind::Interrupted => continue,
                _ => break,
            },
        }
    }
}

This code doesn't compile, it shows this error but I don't understand how to resolve it. The variable msg doesn't live long enough, because of the uuid inside of it, but why ? I had to add the lifetime because I'm sending uuid inside the channel.

 fn handle_client<'a>(stream: TcpStream, sender: mpsc::Sender<&'a [u8]>, uuid: String) {
             -- lifetime `'a` defined here

                sender.send(msg.as_bytes()).unwrap();
                ------------^^^------------
                |           |
                |           borrowed value does not live long enough
                argument requires that `msg` is borrowed for `'a`
                break;
            };
            - `msg` dropped here while still borrowed
saamir
  • 13
  • 3

1 Answers1

0

Uuid does not affect msg because format macro creates a clean new String. You are trying to send a &[u8] (this is what as_bytes() return). You need to find a way to remove this reference. (maybe this something like How to convert from &[u8] to Vec<u8>?) You can also share references with Rc.

PS: this more a comment than an answer but I can't post answers

Mubelotix
  • 81
  • 4