c# java socketn 字节流_socket传输protobuf字节流的实例详解

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

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

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

首先的拼接数据包

1 /// 2 /// 构建消息数据包 3 /// 4 /// 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()方法

57b0a74d9de23120672eccf80dbe859f.gif

0767bfe467889be3f00507557bfd1f04.gif

1 using System; 2 using System.Collections.Generic; 3 4 /// 5 /// 字节缓冲处理类,本类仅处理大字节序 6 /// 警告,本类非线程安全 7 /// 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 pool = new List(); 25 private static int poolMaxCount = 200; 26 //此对象是否池化 27 private bool isPool = false; 28 29 /// 30 /// 构造方法 31 /// 32 /// 初始容量 33 private ByteBuffer(int capacity) 34 { 35 buf = new byte[capacity]; 36 this.capacity = capacity; 37 } 38 39 /// 40 /// 构造方法 41 /// 42 /// 初始字节数组 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 /// 52 /// 构建一个capacity长度的字节缓存区ByteBuffer对象 53 /// 54 /// 初始容量 55 /// ByteBuffer对象 56 public static ByteBuffer Allocate(int capacity) 57 { 58 return new ByteBuffer(capacity); 59 } 60 61 /// 62 /// 构建一个以bytes为字节缓存区的ByteBuffer对象,一般不推荐使用 63 /// 64 /// 初始字节数组 65 /// ByteBuffer对象 66 public static ByteBuffer Allocate(byte[] bytes) 67 { 68 return new ByteBuffer(bytes); 69 } 70 71 /// 72 /// 获取一个池化的ByteBuffer对象,池化的对象必须在调用Dispose后才会推入池中,否则此方法等同于Allocate(int capacity)方法,此方法为线程安全的 73 /// 74 /// ByteBuffer对象的初始容量大小,如果缓存池中没有对象,则对象的容量大小为此值,否则为池中对象的实际容量值 75 /// 76 public static ByteBuffer GetFromPool(int capacity) 77 { 78 lock (pool) 79 { 80 ByteBuffer bbuf; 81 if (pool.Count == 0) 82 { 83 bbuf = Allocate(capacity); 84 bbuf.isPool = true; 85 return bbuf; 86 } 87 int lastIndex = pool.Count - 1; 88 bbuf = pool[lastIndex]; 89 pool.RemoveAt(lastIndex); 90 if (!bbuf.isPool) 91 { 92 bbuf.isPool = true; 93 } 94 return bbuf; 95 } 96 } 97 98 /// 99 /// 根据length长度,确定大于此leng的最近的2次方数,如length=7,则返回值为8100 /// 101 /// 参考容量102 /// 比参考容量大的最接近的2次方数103 private int FixLength(int length)104 {105 int n = 2;106 int b = 2;107 while (b < le

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值