Modified TcpListener program to allow for two different ports - bugs .

People,

I am just getting started (again) and I have modified a working TcpListener program to allow for two different ports to be monitored but there are some bugs . . I copied most of the code out of the main module and created a new function so I could re-use code but I am obviously missing something. The code is below but when I run the program it exits instead of listening with this (inc debug statements):

$ ./t201_tcp_server
TcpListener { addr: V4(0.0.0.0:3333), fd: 3 }
Server listening on port 3333
Server listening on port 3334
In handle_listener
TcpListener { addr: V4(0.0.0.0:3333), fd: 3 }

Help appreciated!

Phil.

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


fn handle_client(mut stream: TcpStream) {
	println!("In handle_client") ;
	println!("{:?}", stream) ;

	let mut data = [0 as u8; 50]; // using 50 byte buffer

	while match stream.read(&mut data) {
		Ok(size) => {
			// echo everything!
			stream.write(&data[0..size]).unwrap();
			true
		},
		Err(_) => {
			println!("An error occurred, terminating connection with {}", stream.peer_addr().unwrap());
			stream.shutdown(Shutdown::Both).unwrap();
			false
		}
	} {}
}


fn handle_listener(listener: TcpListener) {
	println!("In handle_listener") ;
	println!("{:?}", listener) ;

	for stream in listener.incoming() {
		println!("New stream") ;
		match stream {
			Ok(stream) => {
				println!("New connection: {}", stream.peer_addr().unwrap());

				thread::spawn(move|| {
					// connection succeeded
					handle_client(stream)
				});
			}
			Err(e) => {
				println!("Error: {}", e);
				/* connection failed */
			}
		}
	}
}


fn main() {
	let listener1 = TcpListener::bind("0.0.0.0:3333").unwrap();
	// accept connections and process them, spawning a new thread for each one
	println!("{:?}", listener1) ;

	println!("Server listening on port 3333");
	thread::spawn(move|| {
		handle_listener(listener1)
	});

	let listener2 = TcpListener::bind("0.0.0.0:3334").unwrap();
	// accept connections and process them, spawning a new thread for each one

	println!("Server listening on port 3334");
	thread::spawn(move|| {
		handle_listener(listener2)
	});
/*
	// close the socket server
	drop(listener1);
*/
}

When the main thread exists the whole process exits. This is the case on almost any OS I know of. You will have to call .join() on the values returned by both thread::spawn to wait for the threads to exit before exiting the process.

@bjorn3 ,

Ah yes that would make sense . . I can't get the syntax of the join right though . .

Also, however, there is an earlier problem - in handle_listener the first thread does not make it to:

println!("In handle_listener") ;

. . not sure why not . .

Thanks!

That is probably that the process exited before the spawned thread had a chance to run.

Something like

let thread1 = thread::spawn(move || {
    // ...
});

let thread2 = thread::spawn(move || {
    // ...
});

thread1.join().unwrap();
thread2.join().unwrap();
1 Like

@bjorn3 ,

Right.

Success! - many thanks for that help!

Oh . . one more thing - the original single-threaded code had a final:

drop(listener);

but now that identity has been moved so how to drop now? - the code is working without drops but it is good to know anyway . .

Thanks,

Phil.

When you did thread::spawn(move || { /* ... */ }) the move means that all variables used inside the closure are moved onto the closure, so listener1 is moved into the thread that uses it. This means that you can only drop listener1 from that thread.

@bjorn3 ,

So it has gone out of scope and "dropped" when the thread terminates?

Thanks.

The closure of thread::spawn moves listener1 to handle_listener. handle_listener doesn't move ot further so when handle_listener returns listener gets dropped.

@bjorn3 ,

OK, that makes sense . .

Thanks!