原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款 C# 语言编写的 TCP/UDP 通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是: Apache License v2
开源地址是: https://github.com/MarcFletcher/NetworkComms.Net
首先,使用 TCP 通信的时候存在消息边界的问题,也就是如何处理粘包问题,networkcomms 框架本身已经对这个问题有内置的解决方案,我们在使用框架时直接数据通信即可,不需要关心消息边界问题。
下面我们来分析一下 networkcomms 对消息边界问题是如何进行处理的。
TCP 无保护消息边界的解决
针对这个问题,一般有 3 种解决方案:
(1) 发送固定长度的消息
(2) 把消息的尺寸与消息一块发送
(3) 使用特殊标记来区分消息间隔
NetworkComms 通信框架使用的是第二种 即消息的尺寸与消息一块发送
来看一下这个流程
客户端发送一个类给服务器端
代码如下:
- User user1 = new User();
- user1.UserID = "10000";
- user1.Name = "天涯共此时";
- connection.SendObject("消息类型", user1);
然后 networkcomms 框架开始发送这个类
在 ConnectionSendClose.cs 文件中
判断发送的类,是否是 Packet 类型,如果是使用 SendPacket 进行发送。如果不是,转换成 Packet 类型再发送
- public void SendObject(string sendingPacketType, sendObjectType objectToSend, SendReceiveOptions options, out long packetSequenceNumber) {
- //判断发送的类,是否是Packet类型
- Packet objectToSendAsPacket = objectToSend as Packet;
- if (objectToSendAsPacket == null) {
- //如果不是,转换成Packet类型再发送
- using(Packet sendPacket = new Packet(sendingPacketType, objectToSend, options)) SendPacket(sendPacket, out packetSequenceNumber);
- } else {
- if (objectToSendAsPacket.PacketHeader.PacketType != sendingPacketType) throw new ArgumentException("Unable to send object of type Packet if the PacketHeader.PacketType and sendingPacketType do not match.");
- SendPacket(objectToSendAsPacket, out packetSequenceNumber);
- }
- }
上面的代码中,通过这一句
- Packet sendPacket = new Packet(sendingPacketType, objectToSend, options)把要发送的User类转化为Packet类
- 来分析一下Packet类
- public Packet(string sendingPacketTypeStr, string requestReturnPacketTypeStr, object payloadObject, SendReceiveOptions options) {
- Constructor(sendingPacketTypeStr, requestReturnPacketTypeStr, payloadObject, options, false);
- }
要发送的数据类 (此次为 User 类型数据), 以参数的形式赋值给 Packet.
Packet 类,经过一些类内部处理,User 类数据,最后经过转化存放在 PacketData 属性中,也就是包体数据。
Packet 类中的 SerialiseHeader(SendReceiveOptions options) 返回的是包头(PacketHeader)序列化后的数据
Connection 类中的 SendPacketSpecific 方法会先发送包头数据,再发送包体数据。
我们看一下 Packet 中序列化包头的方法
- /// <inheritdoc />
- public byte[] SerialiseHeader(SendReceiveOptions options) {
- if (options == null) throw new ArgumentNullException("options", "Provided SendReceiveOptions cannot be null.");
- //We need to start of by serialising the header
- //把包头序列化为二进制数组
- byte[] serialisedHeader;
- using(StreamTools.StreamSendWrapper sendWrapper = options.DataSerializer.SerialiseDataObject(_packetHeader, options.DataProcessors, null)) serialisedHeader = sendWrapper.ThreadSafeStream.ToArray(1);
- if (serialisedHeader.Length - 1 > byte.MaxValue) throw new SerialisationException("Unable to send packet as header size is larger than Byte.MaxValue. Try reducing the length of provided packetTypeStr or turning off checkSum validation.");
- //The first byte now specifies the header size (allows for variable header size)
- //包头转化成的二进制数据,第一个字节的值,设定为包头的长度
- serialisedHeader[0] = (byte)(serialisedHeader.Length - 1);
- if (serialisedHeader == null) throw new SerialisationException("Serialised header bytes should never be null.");
- return serialisedHeader;
- }
来源: http://www.cnblogs.com/csdev/p/5797902.html