I'm trying to write an extremely simple concurrent server in Rust to play with the language's concurrency primitives and its threading model. Here's my code:
use std::io::prelude::*;
use std::io::Result;
use std::net::{TcpListener, TcpStream, Shutdown};
use std::sync::{Arc, Mutex};
use std::thread;
fn handle_client(mut stream: TcpStream) -> Result<()> {
try!(stream.write(b"HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 5\r\n\r\nPong!\r\n"));
// try!(stream.shutdown(Shutdown::Both));
Ok(())
}
fn main() {
let listener = TcpListener::bind("127.0.0.1:1337").unwrap();
// let count = Arc::new(Mutex::new(0));
for stream in listener.incoming() {
match stream {
Ok(stream) => {
// let count = count.clone();
thread::spawn(move || {
let _ = handle_client(stream);
// let mut count = count.lock().unwrap();
// *count += 1;
// println!("{:?}", *count);
});
}
Err(e) => {
println!("Error: {}", e);
}
}
}
drop(listener);
}
When I run ab -c 100 -n 100 http://127.0.0.1:1337/
with the program running as listed above, I get apr_socket_recv: Connection reset by peer (104)
almost immediately. Why?
When I add try!(stream.shutdown(Shutdown::Both));
(commented out near the top, above) I no longer get the apr_socket_recv
error like before, but apachebench gives me results that say 199 failed requests due to exceptions. Why? What am I doing wrong?
Concurrency Level: 100
Time taken for tests: 0.008 seconds
Complete requests: 100
Failed requests: 199
(Connect: 0, Receive: 0, Length: 0, Exceptions: 199)
Total transferred: 500 bytes
I believe the problem is that you are not fully reading the data sent from the client, so the client never has a chance to transition to reading the response. When it tries to write more data, it notices the socket has been closed and fails.
I've augmented your example to read all the HTTP headers before replying, ignoring any request body. I'm punting on pretty error handling and just panicking if there are errors:
This works with
ab -c 50 -n 5000 http://127.0.0.1:8080/
:The documentation of TcpStream states that
Since your function ends without properly shutting down the TCP-stream but simply by closing the socket, you get the
Connection reset by peer
error. A full TCP-shutdown requires multiple messages to be sent in both directions. This obviously can't happen anymore since the socket was closed.I don't have an answer for your second question. Also, on stackoverflow you should only ask one question per question.