原文網址: 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<sendObjectType>(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<sendObjectType>(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<sendObjectType>(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