铁锈持久性TcpStream
我似乎在与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连接并在客户端和服务器之间来回发送消息。我在这里误解了什么?我与我正在通信的实际系统有完全相同的问题 - 一旦我终止连接,我只会变得畅通无阻。
不幸的是,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_from
将kind
集中返回IoError
到TimedOut
如果期间内recv_from
来电5秒钟插座上没有可用的数据。您需要在每次循环迭代之前重置超时,因为它更像是一个“最后期限”而不是超时 - 当它到期时,所有调用都将开始失败,并出现超时错误。
这绝对不是它应该完成的方式,但Rust目前没有提供更好的方法。至少它做了它的工作。
更新
现在有一个试图创建基于I/O上的异步事件循环和网络。它被称为mio
。对于异步I/O,它可能是一个很好的临时(或者甚至是永久的,谁知道)的解决方案。
好吧,我将无法做适当的异步I/O ...无赖。但是为什么在连接关闭之前我不能从TcpStream读取数据呢?是否实施了缓冲所有数据直到EOF? – Upio 2014-09-03 07:08:09
@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
对不起,如果我不清楚,我已经知道如何与读者互动。我只想知道为什么没有数据在客户端读取,直到连接关闭。即使我使用read_byte(),它会阻塞直到连接终止。这在内部是如何工作的? – Upio 2014-09-03 07:19:12