SOCKET 封包 和 解包

目标

soecet收发数据封包和解包

背景

一般都有固定长度、固定后缀等做法,但都花里胡哨,有各自的问题。
本文采用数据长度+ 数据buffer模式,其中最简单的是用4字节int来表示长度。但这还不够,很多情况下长度可能一个byte就够用了,浪费了3个字节,本文采用动态字节数来存储长度,至于数据buffer使用protobuf来编码和解码就完事了

详细方案

  1. 首先读取一个字节,也就8个bit,a b c d e f g h
  2. 判断a是否为0,如果是,则长度用1个字节0xxx xxxx表示,那么1个字节能表示的范围是[0, 128{0x80} ),
  3. a=1,继续判断b是否为0,如果是,长度用2个字节10xx xxxx xxxx xxxx表示,2个字节表示的范围是[128, 16k{0x4000} )
  4. a=1,b=1,继续判断c是否为0,如果是,长度用3个字节表示110x xxxx xxxx xxxx xxxx,3个字节表示的范围是[16k, 2M{0x200000} )
  5. a=1,b=1,c=1,此时长度用4个字节表示111x xxxx xxxx xxxx xxxx xxxx xxxx xxxx,4个字节表示的范围是[2M, 512M{0x20000000} )
首字节类型需要字节数范围16进制最大值(不包含)
0xxx xxxx1[0, 128)0x80
10xx xxxx2[128, 16k)0x4000
110x xxxx3[16k, 2M)0x200000
111x xxxx4[2M, 512M)0x20000000

其实绝大部分包的大小是128字节以内,那么将会用1个字节来表示长度,相对原始方案,节省了3个字节

代码

  1. 长度编码

        /// <summary>
        /// 设置一个byte中各个bit的位值
        /// </summary>
        /// <param name="_word">目标,要设置的byte</param>
        /// <param name="value">值,为目标位设置的值</param>
        /// <returns></returns>
        public static byte SetBits(byte _word, byte value)
        {
            return (byte)(_word & ~value | value);
        }

        /// <summary>
        /// 0xxx xxxx [0-128{0x80})  1个字节
        /// 10xx xxxx [128, 16k{0x4000}) 2个字节
        /// 110x xxxx [16k, 2M{0x200000}) 3个字节
        /// 111x xxxx [2M, 512M{0x20000000}) 4个字节
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static byte[] EncodeInt(int value)
        {
            if (value < 0)
            {
                throw new ArgumentException(string.Format("invalid data length < 0, cur_length={0}", value));
            }
            else if (value < 0x80)
            {
                return new byte[] { (byte)value };
            }
            else if (value < 0x4000)
            {
                return new byte[] { SetBits((byte)(value >> 8), 0x80), (byte)value };
            }
            else if (value < 0x200000)
            {
                return new byte[] { SetBits((byte)(value >> 16), 0xC0), (byte)(value >> 8), (byte)value };
            }
            else if (value < 0x20000000)
            {
                return new byte[] { SetBits((byte)(value >> 24), 0xE0), (byte)(value >> 16), (byte)(value >> 8), (byte)(value) };
            }
            else
            {
                throw new ArgumentException(string.Format("invalid data length, max_length({0}), cur_length({1})", 0x20000000, value));
            }
        }
  1. 长度解码

        public static int DecodeInt(byte[] data, int offset, int count, out int lengthByteCount)
        {
            if ((data[offset] & 0x80) == 0)//0xxx xxxx
            {
                lengthByteCount = 1;
                if (count < lengthByteCount) return -1;
                return (int)data[offset];
            }
            else if ((data[offset] & 0x40) == 0)//10xx xxxx
            {
                lengthByteCount = 2;
                if (count < lengthByteCount) return -1;

                return (data[offset] & 0x3F) << 8 | data[offset + 1];
            }
            else if ((data[offset] & 0x20) == 0)//110xx xxxx
            {
                lengthByteCount = 3;
                if (count < lengthByteCount) return -1;
                return (data[offset] & 0x1F) << 16 | data[offset + 1] << 8 | data[offset + 2];
            }
            else//111x xxxx
            {
                lengthByteCount = 4;
                if (count < lengthByteCount) return -1;
                return (data[offset] & 0x1F) << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
            }
        }
    }
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: AAC(Advanced Audio Coding)是一种基于MPEG-2标准的音频压缩编码格式,它采用了高效的压缩算法,能够在保留较高音质的同时减小文件大小。RTP(Real-time Transport Protocol)是一种实时传输音视频数据的协议,用于在互联网上传输音视频流。 AAC封包和解是将AAC音频数据封装成RTP数据,并在接收端将RTP数据解包还原成AAC音频数据的过程。 在进行AAC封包时,需要首先将原始的AAC音频数据按照RTP格式进行封装。封包的过程括以下几个步骤: 1. 分片:将原始的AAC音频数据分成较小的数据块,以便在网络上传输。 2. 添加RTP头部:为每个数据块添加RTP头部,括序列号、时间戳等信息,用于接收端进行数据恢复。 3. 添加RTP扩展头部(可选):添加一些额外的信息,如源地址、目的地址等。 4. 添加UDP头部:将封装好的RTP数据添加UDP头部,以便进行网络传输。 在进行AAC解包时,需要将接收到的RTP数据解析还原成原始的AAC音频数据。解包的过程括以下几个步骤: 1. 去除UDP头部:将接收到的数据去除UDP头部,获取RTP数据。 2. 解析RTP头部:解析RTP头部获取序列号、时间戳等信息。 3. 去除RTP头部:将RTP头部去除,获取原始的AAC音频数据块。 4. 还原AAC音频数据:将获取到的音频数据块还原成原始的AAC音频数据。 封包和解使得AAC音频数据能够以RTP数据的形式在网络上进行实时传输和接收,保证了音频数据的完整性和一定程度的实时性。这对于需要进行音频传输的应用场景非常有用,如实时语音通话、音频会议等。 ### 回答2: RTP(实时传输协议)是一种用于实时数据传输的协议,可以将音频、视频和其他多媒体数据封装并实时传输。AAC(Advanced Audio Coding)是一种高级音频编码格式,能够提供较高的音质和较低的数据率。 在将AAC封装成RTP时,需要进行以下步骤: 1. 分割AAC帧:AAC编码的音频数据通常以帧的形式存储,需要将这些帧进行分割,以便封装成RTP。 2. 添加RTP头部:根据RTP协议的规范,需要为每个AAC帧添加RTP头部,括序列号、时间戳和同步源等信息。 3. 打成RTP:将添加了RTP头部的AAC帧按照一定的顺序和格式打成RTP,可以使用UDP协议进行传输。 解包RTP中的AAC音频数据时,需要进行以下步骤: 1. 解析RTP头部:从接收到的RTP中提取出RTP头部的信息,括序列号、时间戳和同步源等。 2. 解析AAC帧:根据AAC编码的格式,将RTP中的数据解析成原始的AAC帧。 3. 合并帧数据:如果收到多个RTP含有同一帧中的不同部分数据,需要将这些部分数据进行合并,还原出完整的AAC帧。 4. 进行解码:将还原出的AAC帧进行解码,得到音频数据。 5. 进一步处理:可以对解码后的音频数据进行后续处理,如播放、存储或传输。 通过上述封包和解的过程,我们能够将AAC音频数据封装成RTP进行实时传输,并在接收端解析和解RTP,得到原始的AAC音频数据进行后续处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值