Rust 从mio::UDP::UdpSocket.recv接收部分UDP数据包

Rust 从mio::UDP::UdpSocket.recv接收部分UDP数据包,rust,mio,Rust,Mio,我正在使用mio::udp::UdpSocket接收来自客户端的请求响应。看起来我在触发的事件上收到了部分UDP数据包。我不确定这是否是mio库中的bug 我尝试过PollOpt::level()、all()、empty()、edge()等。我想我通常希望level()基于poll()文档,但它们都不起作用。通过增加20毫秒的睡眠时间,我可以得到完整的数据包 作为参考,当使用阻塞std::net::UdpSocket时,我看不到任何问题。老实说,如果std::net::SocketOpts是稳定

我正在使用mio::udp::UdpSocket接收来自客户端的请求响应。看起来我在触发的事件上收到了部分UDP数据包。我不确定这是否是mio库中的bug

我尝试过PollOpt::level()、all()、empty()、edge()等。我想我通常希望level()基于poll()文档,但它们都不起作用。通过增加20毫秒的睡眠时间,我可以得到完整的数据包

作为参考,当使用阻塞std::net::UdpSocket时,我看不到任何问题。老实说,如果std::net::SocketOpts是稳定的,我就使用它。使用mio的目的是在套接字上获得超时,看起来net2将取代std::net,但即使net2在recv上也没有超时

下面是eventloop的代码:

sleep_ms(20);

let mut event_loop: EventLoop<Response> = try!(EventLoop::new());

if event_loop.timeout_ms((), 5000).is_err() { return Err(ClientError::TimerError) };
try!(event_loop.register_opt(&self.socket, RESPONSE, EventSet::readable(), PollOpt::all()));

let mut response: Response = Response::new(&self.socket);

try!(event_loop.run_once(&mut response));
sleep_ms(20);
让mut event_循环:EventLoop=try!(EventLoop::new());
if event_loop.timeout_ms((),5000).is_err(){return err(ClientError::TimerError)};
尝试(event_loop.register_opt(&self.socket,RESPONSE,EventSet::readable(),PollOpt::all());
让mut响应:response=response::new(&self.socket);
尝试(event_loop.run_once(&mut response));
以下是处理程序的代码:

fn ready(&mut self, _: &mut EventLoop<Self>, token: Token, events: EventSet) {
  match token {
    RESPONSE => {
      if !events.is_readable() {
        debug!("got woken up, but not readable: {:?}", token);
        return
      }

      let recv_result = self.socket.recv_from(&mut self.buf);
      if recv_result.is_err() {
        // debug b/c we're returning the error explicitly
        debug!("could not recv_from on {:?}: {:?}", self.socket, recv_result);
        self.error = Some(recv_result.unwrap_err().into());
        return
      }

      if recv_result.as_ref().unwrap().is_none() {
        // debug b/c we're returning the error explicitly
        debug!("no return address on recv_from: {:?}", self.socket);
        self.error = Some(ClientError::NoAddress);
        return
      }

      let addr = Some(recv_result.unwrap().unwrap());
      debug!("bytes: {:?} from: {:?}", self.buf.len(), addr);
    },
    _ => error!("unrecognized token: {:?}", token),
  }
}
fn就绪(&mut self,&mut EventLoop,token:token,events:EventSet){
匹配令牌{
响应=>{
if!events.is_可读(){
调试!(“已唤醒,但不可读:{:?}”,标记);
返回
}
让recv_result=self.socket.recv_from(&mut self.buf);
if recv_result.is_err(){
//调试b/c我们显式返回错误
调试!(“无法从{:?}:{:?},self.socket,recv_结果上接收到);
self.error=Some(recv_result.unwrap_err().into());
返回
}
如果recv_result.as_ref().unwrap()为_none(){
//调试b/c我们显式返回错误
debug!(({:?},self.socket)的recv_上没有返回地址);
self.error=Some(ClientError::NoAddress);
返回
}
让addr=Some(recv_result.unwrap().unwrap());
调试!(“字节:{:?}from:{:?}”,self.buf.len(),addr);
},
_=>错误!(“无法识别的令牌:{:?}”,令牌),
}
}

接下来,上面逻辑中的错误是run_once()只运行了一个滴答声,而不是一个“事件”,这是一个错误的假设(尽管公平地说,接口目前没有很好的文档记录)

在任何情况下,这都不是部分数据包问题,而是在run_once()逻辑运行之前,数据包没有被传递,在套接字上没有看到任何内容,并且立即返回


在收到数据包并使用run()而不是run\u once()后,我已将处理程序更改为执行事件循环.shutdown()。

我建议通过分析线路上的UDP数据包,100%确认您试图获取的所有数据都是在单个数据报中发送的。谢谢,我会再次检查,但我们讨论的大小是129字节。这是标准MTU的方式。MTU与任何事情都无关。这就决定了如何将数据包分解成数据包。我让你确认它是用一个数据报发送的。这将取决于发送软件的工作方式,因为数据报是应用程序级的东西。是的,数据报如何映射到数据包取决于UDP,但UDP使应用程序看不到。因此,在TCPDump大量使用之后,我认为我遇到了另一个问题,我的测试出于某种原因提前关闭套接字。看起来我的客户端在接收到来自远程端的数据包响应后正在回滚ICMP数据包。这意味着我误用了run_once()方法,我原以为这意味着只运行一个事件,但我猜现在这意味着运行一次,这会导致客户端在收到数据包之前返回。我需要重新思考我管理客户端事件的方式。是的,就是这样。。。这里的bug是run_once()的滥用,与部分数据包无关。我错误地识别了正在发生的EOF错误,这意味着我还需要修正缓冲区管理的逻辑,以确保我不会有被填充、未填充或从未收到任何内容的问题。谢谢你的帮助!