我有以下 Rust Tokio UDP Echo 服务器示例。不幸的是,我无法关闭对客户端的回声。我只想接收消息,但不想向客户端发送任何内容。我必须如何调整以下源代码?感谢您的帮助。
#![warn(rust_2018_idioms)]
use std::error::Error;
use std::net::SocketAddr;
use std::{env, io};
use tokio::net::UdpSocket;
struct Server {
socket: UdpSocket,
buf: Vec<u8>,
to_send: Option<(usize, SocketAddr)>,
}
impl Server {
async fn run(self) -> Result<(), io::Error> {
let Server {
socket,
mut buf,
mut to_send,
} = self;
loop {
// First we check to see if there's a message we need to echo back.
// If so then we try to send it back to the original source, waiting
// until it's writable and we're able to do so.
if let Some((size, peer)) = to_send {
let amt = socket.send_to(&buf[..size], &peer).await?;
println!("Echoed {}/{} bytes to {}", amt, size, peer);
}
// If we're here then `to_send` is `None`, so we take a look for the
// next message we're going to echo back.
to_send = Some(socket.recv_from(&mut buf).await?);
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let addr = env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:8080".to_string());
let socket = UdpSocket::bind(&addr).await?;
println!("Listening on: {}", socket.local_addr()?);
let server = Server {
socket,
buf: vec![0; 1024],
to_send: None,
};
// This starts the server task.
server.run().await?;
Ok(())
}
源代码来自:https://github.com/tokio-rs/tokio/blob/master/examples/echo-udp.rs
答案 0 :(得分:0)
所有实际的消息处理都在 Servers loop
函数的 run
中完成,因此我将只关注那部分以缩短答案。
loop {
if let Some((size, peer)) = to_send {
println!("Received {} from {}", std::str::from_utf8(&buf[..size]), peer);
}
to_send = Some(socket.recv_from(&mut buf).await?);
}
了解 Rust 异步的工作原理很重要。我强烈建议您在此处阅读 Rust Async 书籍:https://rust-lang.github.io/async-book/
变量 to_send
在主函数中使用 Option 值 None
进行初始化(因为它存储在 Server 结构中,所以实例化就完成了)。
所以第一次循环运行时 if let Some(...) = to_send
不会执行,因为 to_send
不是 Some
。所以它直接跳转到 recv_from
行。
基本上这里发生的所有事情都是使用 await
程序等待 recv_from
返回一个元组,其中包含接收到的字节数和消息来自的对等体,该元组被包装在一个Some
值(如果您不知道它是如何工作的,请查看 Rust 枚举和 Rust 选项的工作原理)。 recv_from
将在收到消息时返回该信息,并将消息的字节写入参数指定的数组中。 &mut buf
是对 buf
的可变引用,提供给 recv_from
以写入该数组。
因此,当到达循环结束并再次开始时,to_send
现在将拥有一个 Some
值,其中包含具有字节数和对等体的元组。在原始代码中,它现在通过 send_to
发送到客户端,但是您也可以使用 std::str::from_utf8(...)
将该消息转换为 uf8 字符串并为其提供字节数组。为了让函数知道该数组的实际长度,创建了一个所谓的拼接,它仅表示具有接收字节长度的数组的一部分。
然后可以将结果字符串打印到控制台并可以接收下一条消息。