首页 > 解决方案 > 仅读取 fifo 中的部分缓冲区 (VecDeque)

问题描述

假设我有一个

packets: VecDeque<Packet>

这是 tcp 数据包的先进先出。也就是说,客户端每次都从这个双端队列中读取,获取最旧的缓冲区,然后填充一个缓冲区,如下所示:


fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut tokio::io::ReadBuf<'_>,
    ) -> Poll<std::io::Result<()>> {
        buf.put_slice(self.packets.front().unwrap().internal_slice)
}

这里有问题。如果buf的容量小于internal_slice,它会恐慌。因此,我们不能简单地依赖获得front()每次。消耗部分VecDeque最旧缓冲区的最佳方法是什么?

我想得到前面,如果缓冲区太大,只复制它的一部分然后放回去并在内部更新一些东西Packet,但是有没有更好、更不容易出错的方法呢?也不需要复制并放回去,这会复制缓冲区太多次。

标签: rust

解决方案


您可以bytes::Bytes在数据包中使用。您的代码可能如下所示:

// imports for bytes
use bytes::{Bytes, Buf};

fn poll_read(
    self: Pin<&mut Self>,
    cx: &mut Context<'_>,
    buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {

    let front_packet = match self.packets.front_mut() {
        Some(p) => p,
        None => return Poll::Ready(Ok(()))
    };
    let bytes = &mut front_packet.bytes;

    // the len that can be written
    let len = buf.remaining()
        .min(bytes.len());

    buf.put_slice(&bytes[..len]);
    bytes.advance(len);

    if bytes.is_empty() {
        // bytes is empty because we could write everything
        let _ = self.packets.pop_front();
    }

     Poll::Ready(Ok(()))
}

使用此代码,您可以将数据包的每个部分复制一次。我个人会说,很容易推理这段代码并确定它是否包含错误。

如果您不想使用bytes::Bytes,可以使用Cursor<Box<[u8]>>

// imports for cursor
use std::io::{Cursor, Read, BufRead};

fn poll_read(
    self: Pin<&mut Self>,
    cx: &mut Context<'_>,
    buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {

    let front_packet = match self.packets.front_mut() {
        Some(p) => p,
        None => return Poll::Ready(Ok(()))
    };
    // bytes is of type Cursor<Box<[u8]>>
    let bytes = &mut front_packet.bytes;
    let slice = bytes.fill_buf().unwrap();
    // same as bytes.get_ref()[bytes.position()..]

    // the len that can be written
    let len = buf.remaining()
        .min(slice.len());

    buf.put_slice(&slice[..len]);
    bytes.consume(len);
    let slice = &slice[len..];

    if slice.is_empty() {
        // slice is empty because we could write everything
        let _ = self.packets.pop_front();
    }

     Poll::Ready(Ok(()))
}

文档


推荐阅读