我似乎在与std :: io :: TcpStream挣扎。我实际上尝试与另一个系统打开TCP连接,但下面的代码完全模拟了问题。
我有一个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连接很长一段时间,并在客户端和服务器之间来回发送消息。我在这里误解了什么?我与我正在进行通信的真实系统存在完全相同的问题 - 一旦我终止连接,我才会被解锁。
答案 0 :(得分: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_from
调用内5秒内套接字上没有可用数据,IoError
将kind
设置为TimedOut
,将返回recv_from
。你需要在每次循环迭代之前重置超时,因为它更像是一个“截止日期”而不是超时 - 当它到期时,所有调用都会因超时错误而开始失败。
这绝对不是它应该做的方式,但Rust目前没有提供更好的东西。至少它做了它的工作。
<强>更新强>
现在尝试基于它创建异步事件循环和网络I / O.它被称为are。它可能是异步I / O的一个好的临时(甚至永久,谁知道)解决方案。