rust - 仅读取 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
,但是有没有更好、更不容易出错的方法呢?也不需要复制并放回去,这会复制缓冲区太多次。
解决方案
您可以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(()))
}
文档
推荐阅读
- javascript - 从今天到一周后生成工作日
- sql - 默认情况下将数值更改为科学计数法的列
- swift - SwipeCellKit 删除 tableView 中的最后一行创建错误
- c# - C# ASP.NET 表单查询:如何将复选框列表中的多个列表项获取到 SQL 查询中以输出到 Gridview
- c# - 使用 C# 静默卸载 InstallShield Installscript MSI 程序
- javascript - 反应原生组件之间的导航
- java - JPA 和 Hibernate 缺少 INNER JOIN ON 子句
- reactjs - 在没有 setState 的情况下反应状态数组对象的变化
- r - 计算R中数据框中每个组的总和和最小值最大值
- sql-server - SQL Server - 比较 2 个表中存在于相同列中的数据而不检查是否相等