如何查看 bytes::BytesMut 中的大端值?

How do I peek a big endian value from bytes::BytesMut?

我正在将我的一些旧代码转换为 futures async/await 样式,但遇到了问题。

我正在使用 tokio_util 板条箱,因为我正在处理一个框架协议,该协议具有来自该板条箱的 EncoderDecoder 特征。

对于 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);
    }

}

rust.playground

经过一些实验后,我认为这可能是执行此操作的最佳方法。从 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::BytesMutstd::io::Cursorget_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)
    }
}