2015-10-27 11 views
6

との単純なRust HTTPサーバーベンチマーク言語の並行処理プリミティブとそのスレッドモデルで再生するために、非常に単純な同時サーバーをRustで作成しようとしています。私はプログラムを実行してab -c 100 -n 100 http://127.0.0.1:1337/を実行すると、上記のよう「ピアによる接続リセット」ab

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

が、私はほとんどすぐに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 
+0

、あなたのコンテンツの長さが5ではない、それは\ 7(あなたが最後逃したですr \ n)。しかし、これがエラーの理由であるとは考えにくいと思います... –

+0

冗長モードで実行することができます(コマンドラインに '-v'フラグを追加してください)? 2/3のリクエストが失敗したのは不思議です...もしそれらのすべてが失敗したら私は理解していたでしょう... –

+0

'' use std :: io :: Result'に対して、 'Result'タイプです。代わりに 'std :: io'と' io :: Result'を使うことをお勧めします。また、 'drop'を明示的に使う必要はほとんどありません。値は、定義されているスコープの最後に自動的にドロップされます。 – Shepmaster

答えて

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) 
0

documentation of TcpStream状態

値がドロップされるときに、ソケットがクローズされています。

機能はTCPストリームを正しくシャットダウンせずに終了するだけで、ソケットを閉じるだけで、Connection reset by peerエラーが発生します。完全なTCPシャットダウンでは、複数のメッセージを両方向で送信する必要があります。ソケットが閉じられたので、これは明らかにもう起こり得ません。

私はあなたの2番目の質問に対する答えはありません。また、stackoverflowであなたは質問ごとに1つの質問をする必要があります。

+0

これはひどく疑わしいようです。 'Drop'実装が適切な方法でTCP接続を閉じないようにするのはかなり悪い設計です。 – Shepmaster

+0

もしそうでなければ、 'Drop :: drop'コールが終了するのに任意の時間がかかるかもしれません。いずれの行動も完璧ではありませんが、このようにして決定論的です。 –

+0

それでは、TCPを尊重して、どのようにしてソケットを適切に閉じなければなりませんか? – Shepmaster

関連する問題