using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading.Tasks; namespace NetFrame { public class SerializeUtil { 对象序列化 [] encode(object value) { MemoryStream ms = new MemoryStream();//创建编码解码的内存流对象 BinaryFormatter bw = new BinaryFormatter();//二进制流序列化对象 //将obj对象序列化成二进制数据 写入到 内存流 bw.Serialize(ms, value); byte[] result=new byte[ms.Length]; //将流数据 拷贝到结果数组 Buffer.BlockCopy(ms.GetBuffer(), 0, result, 0, (int)ms.Length); ms.Close(); return result; } 反序列化为对象 decode(byte[] value) { MemoryStream ms = new MemoryStream(value);//创建编码解码的内存流对象 并将需要反序列化的数据写入其中 BinaryFormatter bw = new BinaryFormatter();//二进制流序列化对象 result= bw.Deserialize(ms); ms.Close(); return result; } } }
相应的,我们利用上面写好的序列化和反序列化方法将我们再Socket模型中定义的message消息体进行序列化与反序列化
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace NetFrame.auto { public class MessageEncoding { 消息体序列化 [] encode(object value) { SocketModel model = value as SocketModel; ByteArray ba = new ByteArray(); ba.write(model.type); ba.write(model.area); ba.write(model.command); (model.message != null) { ba.write(SerializeUtil.encode(model.message)); } byte[] result = ba.getBuff(); ba.Close(); return result; } 消息体反序列化 decode(byte[] value) { ByteArray ba = new ByteArray(value); SocketModel model = new SocketModel(); byte type; int area; int command; //从数据中读取 三层协议 读取数据顺序必须和写入顺序保持一致 ba.read(out type); ba.read(out area); ba.read(out command); model.type = type; model.area = area; model.command = command; (ba.Readnable) { byte[] message; //将剩余数据全部读取出来 ba.read(out message, ba.Length - ba.Position); //反序列化剩余数据为消息体 model.message = SerializeUtil.decode(message); } ba.Close(); return model; } } }
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace NetFrame { 将数据写入成二进制 ByteArray { MemoryStream ms = new MemoryStream(); BinaryWriter bw; BinaryReader br; public void Close() { bw.Close(); br.Close(); ms.Close(); } 支持传入初始数据的构造 ByteArray(byte[] buff) { ms = new MemoryStream(buff); bw = new BinaryWriter(ms); br = new BinaryReader(ms); } 获取当前数据 读取到的下标位置 Position { get { return (int)ms.Position; } } 获取当前数据长度 Length { get { return (int)ms.Length; } } 当前是否还有数据可以读取 Readnable{ get { return ms.Length > ms.Position; } } 默认构造 ByteArray() { bw = new BinaryWriter(ms); br = new BinaryReader(ms); } public void write(int value) { bw.Write(value); } public void write(byte value) { bw.Write(value); } public void write(bool value) { bw.Write(value); } public void write(string value) { bw.Write(value); } public void write(byte[] value) { bw.Write(value); } public void write(double value) { bw.Write(value); } public void write(float value) { bw.Write(value); } public void write(long value) { bw.Write(value); } value) { value= br.ReadInt32(); } value) { value = br.ReadByte(); } value) { value = br.ReadBoolean(); } value) { value = br.ReadString(); } [] value,int length) { value = br.ReadBytes(length); } value) { value = br.ReadDouble(); } value) { value = br.ReadSingle(); } value) { value = br.ReadInt64(); } public void reposition() { ms.Position = 0; } 获取数据 [] getBuff() { byte[] result = new byte[ms.Length]; Buffer.BlockCopy(ms.GetBuffer(), 0, result, 0, (int)ms.Length); return result; } } }
粘包出现原因:在流传输中出现(UDP不会出现粘包,因为它有消息边界)
1 发送端需要等缓冲区满才发送出去,造成粘包
2 接收方不及时接收缓冲区的包,造成多个包接收
所以这里我们需要对粘包长度进行编码与解码,具体的代码如下: