Rust Tokio future从一个通道读取数据,并使用poll\u fn和try\u ready,这永远不会完成
我有一个永远不会完成的东京未来(Rust Tokio future从一个通道读取数据,并使用poll\u fn和try\u ready,这永远不会完成,rust,future,rust-tokio,Rust,Future,Rust Tokio,我有一个永远不会完成的东京未来(rx是一个Receiver,sock是一个东京UdpSocket)。它基本上从数据包队列中读取数据包,并通过套接字进行传输: poll_fn(move || { match try_ready!(rx .poll() .map_err(|_e| tokio::io::Error::new(tokio::io::ErrorKind::Other, "Poll error"))) { Some((pack
rx
是一个Receiver
,sock
是一个东京UdpSocket
)。它基本上从数据包队列中读取数据包,并通过套接字进行传输:
poll_fn(move || {
match try_ready!(rx
.poll()
.map_err(|_e| tokio::io::Error::new(tokio::io::ErrorKind::Other, "Poll error")))
{
Some((packet, to)) => {
println!(
"Rx: Received {} bytes for {}: {:?}",
packet.len(),
to,
packet.as_slice(),
);
try_ready!(sock.poll_send_to(packet.as_slice(), &to));
println!("Sent");
}
None => println!("Rx end"),
}
Ok(futures::Async::Ready(()))
})
.map_err(|e: tokio::io::Error| println!("Error: {:?}", e))
它一直执行到poll\u send\u to
行(执行poll\u send\u to
之前的println!
之后的println!
不会执行),然后一直等待,不发送数据包
我将上述未来替换为以下未来,以确保它不是套接字问题(我认为以前的通知存在一些问题):
这个未来工作得很好——它按预期发送数据包并退出程序
鉴于rx
可以poll
成功并打印println
消息,我认为问题不在于消息通道。我不认为问题出在插座上,因为第二个未来是可行的。我通过Wireshark直接观察数据包,所以我认为这也不是我观察的问题
我对Rust和Tokio还很陌生,所以我可能忽略了一些基本事实(例如,在同一个未来不能尝试两次,未来不会从之前中断的地方恢复,等等)
你能帮我解决第一个未来的问题吗
use futures::future::lazy;
use futures::stream::Stream;
use futures::try_ready;
use std::net::SocketAddr;
use std::str::FromStr;
use tokio;
use tokio::net::UdpSocket;
use tokio::prelude::future::poll_fn;
use tokio::prelude::Future;
fn main() {
let mut sock = UdpSocket::bind(&SocketAddr::from_str("127.0.0.1:8000").expect("Parse error"))
.expect("Bind error");
let (mut tx, mut rx) = tokio::sync::mpsc::channel::<(Vec<u8>, SocketAddr)>(2000);
tokio::run(lazy(move || {
//----------------- This future works ----------------//
// tokio::spawn(
// poll_fn(move || {
// let packet = vec![70; 10];
// let to = SocketAddr::from_str("127.0.0.1:8001").expect("Parse error");
// try_ready!(sock.poll_send_to(packet.as_slice(), &to));
// Ok(futures::Async::Ready(()))
// })
// .map_err(|e: tokio::io::Error| println!("Error: {:?}", e)),
// );
//----------------- This future doesn't ----------------//
tokio::spawn(
poll_fn(move || {
match try_ready!(rx
.poll()
.map_err(|_e| tokio::io::Error::new(tokio::io::ErrorKind::Other, "Poll error")))
{
Some((packet, to)) => {
// This is printed
println!(
"Rx: Received {} bytes for {}: {:?}",
packet.len(),
to,
packet.as_slice(),
);
try_ready!(sock.poll_send_to(packet.as_slice(), &to));
// This is never printed
println!("Sent");
}
None => println!("Rx end"),
}
Ok(futures::Async::Ready(()))
})
.map_err(|e: tokio::io::Error| println!("Error: {:?}", e)),
);
//----------------- This future queues a packet ----------------//
tokio::spawn(
poll_fn(move || {
try_ready!(tx.poll_ready());
tx.try_send((
vec![70; 10],
SocketAddr::from_str("127.0.0.1:8001").expect("Parse error"),
))
.expect("Send error");
// Wait permanently so message channel doesn't get disconnected
// Achieved differently in production
Ok(futures::Async::NotReady)
})
.map_err(|e: tokio::sync::mpsc::error::SendError| println!("Error: {:?}", e)),
);
Ok(())
}));
}
use futures::future::lazy;
使用futures::stream::stream;
使用futures::try_ready;
使用std::net::SocketAddr;
使用std::str::FromStr;
使用东京;
使用tokio::net::UdpSocket;
使用东京::前奏::未来::投票;
使用东京:前奏:未来;
fn main(){
让mut sock=UdpSocket::bind(&SocketAddr::from_str(“127.0.0.1:8000”)。预期(“解析错误”)
.expect(“绑定错误”);
let(mut-tx,mut-rx)=东京::同步::mpsc::信道::(2000);
东京:跑(懒)(移动){
//-----------------这个未来是可行的----------------//
//东京:繁殖(
//投票站(移动){
//让packet=vec![70;10];
//let to=SocketAddr::from_str(“127.0.0.1:8001”)。expect(“解析错误”);
//试试准备!(sock.poll\u send\u to(packet.as\u slice(),&to));
//好(未来::异步::就绪(())
// })
//.map_err(| e:tokio::io::Error | println!(“Error:{:?}”,e)),
// );
//-----------------这个未来不会----------------//
东京:繁殖(
投票站(移动){
比赛准备就绪!(rx)
.poll()
.map_err(|e|tokio::io::Error::new(tokio::io::ErrorKind::Other,“轮询错误”))
{
一些((数据包,到))=>{
//这是印刷品
普林顿(
“Rx:接收到{}:{:?}的{}字节”,
packet.len(),
到
packet.as_slice(),
);
试试准备!(sock.poll\u send\u to(packet.as\u slice(),&to));
//这是从未印刷过的
println!(“已发送”);
}
无=>println!(“接收端”),
}
好(未来::异步::就绪(())
})
.map_err(| e:tokio::io::Error | println!(“Error:{:?}”,e)),
);
//-----------------这是一个数据包的队列----------------//
东京:繁殖(
投票站(移动){
试试看准备好了吗!(tx.poll_ready());
tx.try\u发送((
vec![70;10],
SocketAddr::from_str(“127.0.0.1:8001”).expect(“解析错误”),
))
.expect(“发送错误”);
//永久等待,以便消息通道不会断开连接
//在生产中取得不同的成就
正常(未来::异步::未就绪)
})
.map_err(| e:tokio::sync::mpsc::error::senderro | println!(“error:{:?}”,e)),
);
好(())
}));
}
使用此版本的future会显示问题:
tokio::spawn(
future::poll_fn(move || {
eprintln!("Starting poll_fn");
let from_channel = rx
.poll()
.map_err(|_e| tokio::io::Error::new(tokio::io::ErrorKind::Other, "Poll error"));
if let Some((packet, to)) = futures::try_ready!(dbg!(from_channel)) {
futures::try_ready!(dbg!(sock.poll_send_to(packet.as_slice(), &to)));
}
Ok(futures::Async::Ready(()))
})
.map_err(|e: tokio::io::Error| println!("Error: {:?}", e)),
);
以下是稍微清理过的输出:
开始轮询\u fn
[src/main.rs:21]来自_通道=正常(未就绪)
开始投票(fn)
[src/main.rs:21]from_channel=Ok(就绪(一些(/*…*/))
[src/main.rs:22]sock.poll\u send\u to(packet.as\u slice(),&to)=Ok(NotReady)
开始投票(fn)
[src/main.rs:21]来自_通道=正常(未就绪)
简言之:
未来开始了
频道没有准备好任何东西;频道注册一个通知
未来回归
通道获取一个值并通知任务
未来再次开始
通道中有一个值已准备就绪
套接字上的发送尚未准备就绪;套接字注册一个通知
未来回归
套接字被清除并通知任务
未来再次开始
频道没有准备好任何节目;频道注册一个通知
未来回归
频道中不会添加任何其他内容
简而言之,您没有在未来正确维护您的状态机。你需要知道你上一次运行future时走了多远,并在下一次运行时从这一点开始
async
/await
语法之所以备受期待,是因为它将为您编写这些状态机
我不知道您为什么选择使用较低级别的poll
界面。我会使用更高级别的未来的:
tokio::spawn({
rx.fold(sock, |sock, (packet, to)| {
sock.send_dgram(packet, &to)
.inspect(|_| println!("Sent it!"))
.map(|(sock, _)| sock)
.map_err(|e| panic!("Error: {:?}", e))
})
.map(drop)
.map_err(|e| panic!("Error: {:?}", e))
});
基于的未来接口[…]在出错时销毁套接字(和缓冲区)
这是使用基于poll
的界面的一个很好的理由,但我还是会花足够长的时间来实现您自己的未来
tokio::spawn({
rx.fold(sock, |sock, (packet, to)| {
sock.send_dgram(packet, &to)
.inspect(|_| println!("Sent it!"))
.map(|(sock, _)| sock)
.map_err(|e| panic!("Error: {:?}", e))
})
.map(drop)
.map_err(|e| panic!("Error: {:?}", e))
});
struct X(UdpSocket);
struct XSendGram<D> {
sock: Option<UdpSocket>,
data: D,
addr: SocketAddr,
}
impl X {
fn send_dgram<D>(self, data: D, addr: SocketAddr) -> XSendGram<D> {
XSendGram {
sock: Some(self.0),
data,
addr,
}
}
}
impl<D> Future for XSendGram<D>
where
D: AsRef<[u8]>,
{
type Item = (X, usize);
type Error = (X, std::io::Error);
fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
let mut sock = self.sock.take().expect("Future called after success or failure");
match sock.poll_send_to(self.data.as_ref(), &self.addr) {
Ok(Async::Ready(bytes)) => Ok(Async::Ready((X(sock), bytes))),
Ok(Async::NotReady) => {
self.sock = Some(sock); // Restore it for the next call
Ok(Async::NotReady)
}
Err(e) => Err((X(sock), e)),
}
}
}
tokio::spawn({
rx.fold(X(sock), |sock, (packet, to)| {
sock.send_dgram(packet, to)
.inspect(|(_, n)| println!("Sent {} bytes", n))
.then(|r| match r {
Ok((sock, _)) | Err((sock, _)) => future::ok(sock),
})
})
.map(drop)
.map_err(|e| panic!("Error: {:?}", e))
});