【问题标题】:How do I peek a big endian value from bytes::BytesMut?如何从 bytes::BytesMut 中查看大端值?
【发布时间】:2021-03-03 15:04:16
【问题描述】:

我正在将我的一些旧代码转换为期货异步/等待风格,但遇到了问题。

我正在使用 tokio_util crate,因为我正在处理一个带有来自这个 crate 的 EncoderDecoder 特征的框架协议。

对于Decoder,我需要查看传递的bytes::BytesMut 结构的前两个字节,因为这些字节包含帧的长度。但是 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);
        };

如果至少有 2 个字节在 buf 中,则下一步将发生,并且应该以大端格式读取这些字节以继续解码。问题是我看不到如何使用 BytesMut 结构来做到这一点。

【问题讨论】:

  • 我没有看到异步链接
  • 链接是我正在使用使用异步读写的 tokio crate,并且在 tokio_util 中定义了 Decoder trait 签名(使用 bytes crate)。
  • 但你的问题是关于 BytesMut,tokio 是题外话。
  • 不,是 tokio 迫使我使用 BytesMut,所以它参与其中。

标签: rust rust-tokio


【解决方案1】:

经过一些实验,我认为这可能是实现此目的的最佳方式。在standard library documentation 中,它在“from_be_bytes”函数下说“当从切片而不是数组开始时,可​​以使用易出错的转换 API”。

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());

        ...
     }
}

【讨论】:

    【解决方案2】:

    您可以使用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

    【讨论】:

    • 你为什么要给read_u16打2个电话?对read_u16 的一次调用将读取2 个字节并返回u16...
    • 我错过了这部分问题。刚刚展示了一种如何以正确格式读取字节的方法。再次更新我的答案。
    • 感谢您的回答。这很烦人,因为这在以前版本的字节板条箱中非常符合人体工程学,因为我刚刚做了 let size = buf[..2].into_buf().get_u16_be()。
    【解决方案3】:

    bytes crate 已经有你要找的东西了。你只需要引入bytes::Buf trait,这将为bytes::BytesMutstd::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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-09-13
      • 2023-02-24
      • 1970-01-01
      • 2013-11-17
      • 1970-01-01
      • 2013-12-24
      • 2021-10-08
      • 2020-03-29
      • 1970-01-01
      相关资源
      最近更新 更多