2016-08-20 4 views
3

サーバーにはthis codeを使用し、クライアントコードにはthis tutorialを修正しました。クライアントがサーバーに接続すると、クライアントは永遠にブロックされます。先物を使用しているエコーサーバーとクライアントは永遠にブロックします

サーバー:

extern crate futures; 
extern crate futures_io; 
extern crate futures_mio; 

use std::net::SocketAddr; 

use futures::Future; 
use futures_io::{copy, TaskIo}; 
use futures::stream::Stream; 

fn main() { 
    let addr = "127.0.0.1:8080".parse::<SocketAddr>().unwrap(); 

    let mut l = futures_mio::Loop::new().unwrap(); 

    let server = l.handle().tcp_listen(&addr); 

    let done = server.and_then(move |socket| { 
     println!("Listening on: {}", addr); 

     socket.incoming().for_each(|(socket, addr)| { 
      let io = TaskIo::new(socket); 
      let pair = io.map(|io| io.split()); 
      let amt = pair.and_then(|(reader, writer)| { 
       copy(reader, writer) 
      }); 
      amt.map(move |amt| { 
       println!("wrote {} bytes to {}", amt, addr) 
      }).forget(); 

      Ok(()) 
     }) 
    }); 
    l.run(done).unwrap(); 
} 

クライアント:

extern crate futures; 
extern crate futures_io; 
extern crate futures_mio; 

use std::net::SocketAddr; 

use futures::Future; 
use futures_mio::Loop; 

fn main() { 
    let mut lp = Loop::new().unwrap(); 
    let addr = "127.0.0.1:8080".parse::<SocketAddr>().unwrap(); 

    let socket = lp.handle().tcp_connect(&addr); 

    let request = socket.and_then(|socket| { 
     futures_io::write_all(socket, b"Hello!") 
    }); 

    let response = request.and_then(|(socket, _)| { 
     futures_io::read_to_end(socket, Vec::new()) 
    }); 

    let data = lp.run(response).unwrap(); 
    println!("{}", String::from_utf8_lossy(&data)); 
} 

答えて

7

問題は先物とは何の関係もありません。あなたはオープンソケットを持っていて、 "終わりまでそれを読む"ように頼みます。 最終決定は何ですか?この場合、ソケットが閉じているときです。それはいつですか?

トリック質問!

  • サーバーの書き込みソケットが閉じると、クライアントの読み取りソケットが閉じます。
  • サーバーの書き込みソケットは、サーバーの読み取りソケットが閉じると閉じます。
  • クライアントの書き込みソケットが閉じると、サーバーの読み取りソケットが閉じます。

だからいつですか?特にそれを行うコードはないので、ソケットが破棄されると閉じられます。

  • クライアントの書き込みソケットは、クライアントの終了時に閉じます。

したがって、デッドロックです。ソケットの書き込み半分を明示的に閉じることで問題を解決できます。

let response = request.and_then(|(socket, _)| { 
    socket.shutdown(std::net::Shutdown::Write).expect("Couldn't shut down"); 
    read_to_end(socket, Vec::new()) 
}); 
+0

チュートリアルでは使用されていません。どうして? – simbiont666

+0

@ simbiont666クライアントサンプルのHTTPサーバは、ページを送信したとき(サーバがHTTP 1.1キープアライブを使用していない場合)にソケットを閉じるためです。 – Shepmaster

+0

ありがとう! – simbiont666

関連する問題