2014-09-03 67 views
6

我似乎在與std :: io :: TcpStream掙扎。我實際上試圖打開與另一個系統的TCP連接,但下面的代碼完全模擬了這個問題。鐵鏽持久性TcpStream

我有一個Tcp服務器,只需在打開時將「Hello World」寫入TcpStream,然後循環以保持連接打開。

fn main() { 
    let listener = io::TcpListener::bind("127.0.0.1", 8080); 
    let mut acceptor = listener.listen(); 
    for stream in acceptor.incoming() { 

    match stream { 
     Err(_) => { /* connection failed */ } 
     Ok(stream) => spawn(proc() { 
     handle(stream); 
     }) 
    } 
    } 
    drop(acceptor); 
} 

fn handle(mut stream: io::TcpStream) { 
    stream.write(b"Hello Connection"); 
    loop {} 
} 

所有的客戶端都試圖從連接讀取一個字節並打印它。

fn main() { 
    let mut socket = io::TcpStream::connect("127.0.0.1", 8080).unwrap(); 
    loop { 
     match socket.read_byte() { 
     Ok(i) => print!("{}", i), 
     Err(e) => { 
      println!("Error: {}", e); 
      break 
     } 
     } 
    } 
} 

現在的問題是我的客戶端仍然在讀取被阻塞,直到我殺死服務器或關閉TCP連接。這不是我想要的,我需要長時間打開TCP連接並在客戶端和服務器之間來回發送消息。我在這裏誤解了什麼?我與我正在通信的實際系統有完全相同的問題 - 一旦我終止連接,我只會變得暢通無阻。

回答

7

不幸的是,Rust現在沒有任何異步I/O功能。有些企圖糾正這種情況,但它們還遠未完成。也就是說,希望能夠實現真正的異步I/O(提議包括同時選擇I/O源和通道,這將允許通過事件通過I/O操作在I/O操作中阻塞的任務被喚醒儘管目前還不清楚在所有支持的平臺上應該如何實現),但仍然有很多事情要做,而且據我所知,現在沒有什麼可用的。

但是,您可以在某種程度上使用超時模擬此功能。這遠不是最好的解決方案,但它的工作原理。它可能看起來像這樣(從我的代碼庫簡化例子):

let mut socket = UdpSocket::bind(address).unwrap(); 

let mut buf = [0u8, ..MAX_BUF_LEN]; 
loop { 
    socket.set_read_timeout(Some(5000)); 
    match socket.recv_from(buf) { 
     Ok((amt, src)) => { /* handle successful read */ } 
     Err(ref e) if e.kind == TimedOut => {} // continue 
     Err(e) => fail!("error receiving data: {}", e) // bail out 
    } 

    // do other work, check exit flags, for example 
} 

這裏recv_fromkind集中返回IoErrorTimedOut如果期間內recv_from來電5秒鐘插座上沒有可用的數據。您需要在每次循環迭代之前重置超時,因爲它更像是一個「最後期限」而不是超時 - 當它到期時,所有調用都將開始失敗,並出現超時錯誤。

這絕對不是它應該完成的方式,但Rust目前沒有提供更好的方法。至少它做了它的工作。

更新

現在有一個試圖創建基於I/O上的異步事件循環和網絡。它被稱爲mio。對於異步I/O,它可能是一個很好的臨時(或者甚至是永久的,誰知道)的解決方案。

+0

好吧,我將無法做適當的異步I/O ...無賴。但是爲什麼在連接關閉之前我不能從TcpStream讀取數據呢?是否實施了緩衝所有數據直到EOF? – Upio 2014-09-03 07:08:09

+0

@Upio,你不是這樣說的:「現在問題是我的客戶端在讀取前一直處於阻塞狀態,直到我終止服務器或關閉TCP連接」?這是「從TcpStream讀取數據直到連接關閉」,不是嗎?無論如何,'TcpStream'是一個[''Reader'](http://doc.rust-lang.org/std/io/trait.Reader.html),所以它具有['read_to_end()'](http:/ /doc.rust-lang.org/std/io/trait.Reader.html#method.read_to_end)方法,它會消耗所有的流直到它被關閉。那是你需要的嗎? – 2014-09-03 07:11:35

+0

對不起,如果我不清楚,我已經知道如何與讀者互動。我只想知道爲什麼沒有數據在客戶端讀取,直到連接關閉。即使我使用read_byte(),它會阻塞直到連接終止。這在內部是如何工作的? – Upio 2014-09-03 07:19:12