版权声明:本文为原创文章,转载请声明

上一篇主要说的是protobuf字节流的序列化和解析,将protobuf对象序列化为字节流后虽然可以直接传递,但是实际在项目中却不可能真的只是传递protobuf字节流,因为socket的tcp通讯中会出现几个很常见的问题,就是粘包和少包。所谓粘包,简单点说就是socket会将多个较小的包合并到一起发送。因为tcp是面向连接的,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。少包则是指缓存区满后,soket将不完整的包发送到接收端(按我的理解,粘包和少包其实是一个问题)。这样接收端一次接收到的数据就有可能是多个包,为了解决这个问题,在发送数据之前,需要将包的长度也发送出去。于是,包的结构就应该是 消息长度+消息内容。

这一篇,就来说说数据的拼接,干货来了

首先的拼接数据包

 1     /// <summary> 2     /// 构建消息数据包 3     /// </summary> 4     /// <param name="protobufModel"></param> 5     byte[] BuildPackage(IExtensible protobufModel) 6     { 7         if (protobufModel != null) 8         { 9             byte[] b = ProtobufSerilizer.Serialize(protobufModel);10 11             ByteBuffer buf = ByteBuffer.Allocate(b.Length + 4);12             buf.WriteInt(b.Length);13             buf.WriteBytes(b);14             return buf.GetBytes();15         }16         return null;17     }

代码中使用的ByteBuffer工具java中有提供,但是c#中是没有的,源码摘至,不过作者并未在工具中添加获取所有字节码的方法,所以自己添加了一个GetBytes()方法

  1 using System;  2 using System.Collections.Generic;  3   4 /// <summary>  5 /// 字节缓冲处理类,本类仅处理大字节序  6 /// 警告,本类非线程安全  7 /// </summary>  8 public class ByteBuffer  9 { 10     //字节缓存区 11     private byte[] buf; 12     //读取索引 13     private int readIndex = 0; 14     //写入索引 15     private int writeIndex = 0; 16     //读取索引标记 17     private int markReadIndex = 0; 18     //写入索引标记 19     private int markWirteIndex = 0; 20     //缓存区字节数组的长度 21     private int capacity; 22  23     //对象池 24     private static List<ByteBuffer> pool = new List<ByteBuffer>(); 25     private static int poolMaxCount = 200; 26     //此对象是否池化 27     private bool isPool = false; 28  29     /// <summary> 30     /// 构造方法 31     /// </summary> 32     /// <param name="capacity">初始容量</param> 33     private ByteBuffer(int capacity) 34     { 35         buf = new byte[capacity]; 36         this.capacity = capacity; 37     } 38  39     /// <summary> 40     /// 构造方法 41     /// </summary> 42     /// <param name="bytes">初始字节数组</param> 43     private ByteBuffer(byte[] bytes) 44     { 45         buf = bytes; 46         this.capacity = bytes.Length; 47         this.readIndex = 0; 48         this.writeIndex = bytes.Length + 1; 49     } 50  51     /// <summary> 52     /// 构建一个capacity长度的字节缓存区ByteBuffer对象 53     /// </summary> 54     /// <param name="capacity">初始容量</param> 55     /// <returns>ByteBuffer对象</returns> 56     public static ByteBuffer Allocate(int capacity) 57     { 58         return new ByteBuffer(capacity); 59     } 60  61     /// <summary> 62     /// 构建一个以bytes为字节缓存区的ByteBuffer对象,一般不  

socket传输protobuf字节流的实例详解