如何查看 bytes::BytesMut 中的大端值?
How do I peek a big endian value from bytes::BytesMut?
我正在将我的一些旧代码转换为 futures async/await 样式,但遇到了问题。
我正在使用 tokio_util 板条箱,因为我正在处理一个框架协议,该协议具有来自该板条箱的 Encoder
和 Decoder
特征。
对于 Decoder
,我需要查看传递的 bytes::BytesMut
结构的前 2 个字节,因为这些字节包含帧的长度。然而 BytesMut
结构并不容易允许这样做。我的函数是:
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
如果 buf 中至少有 2 个字节,则下一步将发生,并且应以大端格式读取这些字节以继续解码器。问题是我看不出如何使用 BytesMut
结构来做到这一点。
您可以使用byteorder crate
use std::io::Cursor;
use byteorder::{BigEndian, ReadBytesExt};
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = std::io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> std::io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
let mut rdr = Cursor::new(&buf[..]);
let package_length = rdr.read_u16::<BigEndian>()?;
return Ok(None);
}
}
经过一些实验后,我认为这可能是执行此操作的最佳方法。从 standard library documentation 它说 "When starting from a slice rather than an array, fallible conversion APIs can be used" 在 "from_be_bytes" 函数下。
use bytes::BytesMut;
use std::convert::TryInto;
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
let frame_size = u16::from_be_bytes(buf[..2].try_into().unwrap());
...
}
}
bytes crate 中已有您要查找的内容。您只需要引入 bytes::Buf
特性,这将为您提供 bytes::BytesMut
和 std::io::Cursor
的 get_u16()
。
use bytes::{BytesMut, Buf};
use std::io::Cursor;
use tokio_util::codec::Decoder;
struct MyCodec;
struct ServerMessage;
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = std::io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> std::io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
let mut peeker = Cursor::new(&buf[..2]);
let size = peeker.get_u16();
if buf.len() >= (size + 2) as usize {
// swallow the size header
let _ = buf.get_u16();
// read frame bytes
Ok(Some(ServerMessage))
}
Ok(None)
}
}
我正在将我的一些旧代码转换为 futures async/await 样式,但遇到了问题。
我正在使用 tokio_util 板条箱,因为我正在处理一个框架协议,该协议具有来自该板条箱的 Encoder
和 Decoder
特征。
对于 Decoder
,我需要查看传递的 bytes::BytesMut
结构的前 2 个字节,因为这些字节包含帧的长度。然而 BytesMut
结构并不容易允许这样做。我的函数是:
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
如果 buf 中至少有 2 个字节,则下一步将发生,并且应以大端格式读取这些字节以继续解码器。问题是我看不出如何使用 BytesMut
结构来做到这一点。
您可以使用byteorder crate
use std::io::Cursor;
use byteorder::{BigEndian, ReadBytesExt};
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = std::io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> std::io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
let mut rdr = Cursor::new(&buf[..]);
let package_length = rdr.read_u16::<BigEndian>()?;
return Ok(None);
}
}
经过一些实验后,我认为这可能是执行此操作的最佳方法。从 standard library documentation 它说 "When starting from a slice rather than an array, fallible conversion APIs can be used" 在 "from_be_bytes" 函数下。
use bytes::BytesMut;
use std::convert::TryInto;
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
let frame_size = u16::from_be_bytes(buf[..2].try_into().unwrap());
...
}
}
bytes crate 中已有您要查找的内容。您只需要引入 bytes::Buf
特性,这将为您提供 bytes::BytesMut
和 std::io::Cursor
的 get_u16()
。
use bytes::{BytesMut, Buf};
use std::io::Cursor;
use tokio_util::codec::Decoder;
struct MyCodec;
struct ServerMessage;
impl Decoder for MyCodec {
type Item = ServerMessage;
type Error = std::io::Error;
fn decode(&mut self, buf: &mut BytesMut) -> std::io::Result<Option<ServerMessage>> {
if buf.len() <= 2 {
return Ok(None);
};
let mut peeker = Cursor::new(&buf[..2]);
let size = peeker.get_u16();
if buf.len() >= (size + 2) as usize {
// swallow the size header
let _ = buf.get_u16();
// read frame bytes
Ok(Some(ServerMessage))
}
Ok(None)
}
}