使用ab对简单的Rust HTTP服务器进行基准测试时,“通过对等方重置连接”

时间:2015-10-27 05:47:56

标签: multithreading http server rust apachebench

我正在尝试在Rust中编写一个非常简单的并发服务器来使用该语言的并发原语及其线程模型。这是我的代码:

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);
}

当我使用上面列出的程序运行ab -c 100 -n 100 http://127.0.0.1:1337/时,我几乎立即得到apr_socket_recv: Connection reset by peer (104)。为什么呢?

当我添加try!(stream.shutdown(Shutdown::Both));(在上方附近注释掉)时,我不再像以前那样得到apr_socket_recv错误,但是apachebench给了我结果,说明因异常而导致199个请求失败。为什么?我做错了什么?

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

2 个答案:

答案 0 :(得分:7)

我认为问题在于您没有完全读取从客户端发送的数据,因此客户端永远无法转换为阅读响应。当它尝试写入更多数据时,它会注意到套接字已关闭并失败。

我已经扩充了您的示例,以便在回复之前读取所有HTTP标头,忽略任何请求正文。如果有错误的话,我正在努力解决错误:

use std::io::prelude::*;
use std::io::BufReader;
use std::net::{TcpListener, TcpStream};
use std::thread;

fn handle_client(mut stream: TcpStream) {
    // Read all the headers
    for header in BufReader::new(&mut stream).lines() {
        let header = header.unwrap();
        if header == "\r" { break }
    }

    // Write our response
    stream.write_all(b"HTTP/1.0 200 OK\r\n\r\n").unwrap();
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap();

    for stream in listener.incoming() {
        let stream = stream.unwrap();
        thread::spawn(|| {
            handle_client(stream);
        });
    }
}

这适用于ab -c 50 -n 5000 http://127.0.0.1:8080/

Benchmarking 127.0.0.1 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requests


Server Software:
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /
Document Length:        0 bytes

Concurrency Level:      50
Time taken for tests:   1.293 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      95000 bytes
HTML transferred:       0 bytes
Requests per second:    3868.22 [#/sec] (mean)
Time per request:       12.926 [ms] (mean)
Time per request:       0.259 [ms] (mean, across all concurrent requests)
Transfer rate:          71.77 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    6   1.7      6      14
Processing:     1    6   1.7      6      14
Waiting:        1    6   1.7      6      14
Total:          5   13   2.6     12      23

Percentage of the requests served within a certain time (ms)
  50%     12
  66%     13
  75%     13
  80%     14
  90%     17
  95%     19
  98%     21
  99%     22
 100%     23 (longest request)

答案 1 :(得分:0)

documentation of TcpStream表示

  

当值被删除时,套接字将被关闭。

由于您的功能在没有正确关闭TCP流的情况下结束,只需关闭套接字,就会出现Connection reset by peer错误。完全TCP关闭需要在两个方向上发送多条消息。由于套接字已关闭,这显然不会再发生了。

我的第二个问题没有答案。此外,在stackoverflow上,您应该只针对每个问题提出一个问题。