Получение частичных пакетов UDP от mio::udp::UdpSocket.recv
Я использую mio::udp::UdpSocket, чтобы получить ответ на запрос от клиента. Похоже, я получаю частичные UDP-пакеты при сработавшем событии. Я не уверен, является ли это ошибкой в библиотеке mio или нет.
Я пробовал PollOpt::level(), all(), empty(), edge() и т. Д. Я думаю, что я обычно хочу level () на основе документов poll(), но ни один из них не работает. Добавляя время ожидания 20 мс, я получаю полные пакеты.
В качестве ссылки, при использовании блокировки std::net::UdpSocket я не вижу проблем. Честно говоря, если бы std::net::SocketOpts был стабильным, я бы просто использовал это. Цель использования mio - получить тайм-аут в сокете, похоже, что net2 заменит std:: net, но даже у net2 нет тайм-аута в recv.
Вот код для цикла событий:
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));
Вот код для обработчика:
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),
}
}
1 ответ
Просто для продолжения, ошибка в вышеприведенной логике заключается в том, что run_once() работает для галочки, а не для одного "события", что было неверным предположением (хотя, чтобы быть справедливым, интерфейс в настоящее время плохо документирован).
В любом случае, это не частичная проблема с пакетом, это проблема того, что пакет не был доставлен до запуска логики run_once(), ничего не увидел в сокете и сразу же вернулся.
Я изменил свой обработчик так, чтобы он делал event_loop.shutdown() после получения пакета и использования run () вместо run_once().