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