东京 UDP 服务器

时间:2021-07-28 06:58:55

标签: rust udp rust-tokio

我有以下 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

1 个答案:

答案 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 字符串并为其提供字节数组。为了让函数知道该数组的实际长度,创建了一个所谓的拼接,它仅表示具有接收字节长度的数组的一部分。

然后可以将结果字符串打印到控制台并可以接收下一条消息。

相关问题