本文基於networkcomms2.3.1開源版本 gplv3協議
在networkcomms中,服務器端可以同步監聽數據,也可以異步監聽數據。
以開源的networkcomms.2.31為例
服務器端監聽代碼:
protected override void StartIncomingDataListen()
{
if (!NetworkComms.ConnectionExists(ConnectionInfo.RemoteEndPoint, ConnectionType.TCP))
{
CloseConnection(true, 18);
throw new ConnectionSetupException("A connection reference by endPoint should exist before starting an incoming data listener.");
}
#if WINDOWS_PHONE
var stream = socket.InputStream.AsStreamForRead();
stream.BeginRead(dataBuffer, 0, dataBuffer.Length, new AsyncCallback(IncomingTCPPacketHandler), stream);
#else
lock (delegateLocker)
{
//同步監聽模式
if (NetworkComms.ConnectionListenModeUseSync)
{
if (incomingDataListenThread == null)
{
incomingDataListenThread = new Thread(IncomingTCPDataSyncWorker);
//Incoming data always gets handled in a time critical fashion
incomingDataListenThread.Priority = NetworkComms.timeCriticalThreadPriority;
incomingDataListenThread.Name = "IncomingDataListener";
incomingDataListenThread.Start();
}
}
//異步監聽模式
else
tcpClientNetworkStream.BeginRead(dataBuffer, 0, dataBuffer.Length, new AsyncCallback(IncomingTCPPacketHandler), tcpClientNetworkStream);
}
#endif
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Listening for incoming data from " + ConnectionInfo);
}
我們以異步監聽為例,分析一下監聽進入的數據的過程(同步監聽類似)
/// <summary>
/// Asynchronous incoming connection data delegate
/// </summary>
/// <param name="ar">The call back state object</param>
void IncomingTCPPacketHandler(IAsyncResult ar)
{
//Initialised with true so that logic still works in WP8
bool dataAvailable = true;
#if !WINDOWS_PHONE
//Incoming data always gets handled in a timeCritical fashion at this point
Thread.CurrentThread.Priority = NetworkComms.timeCriticalThreadPriority;
//int bytesRead;
#endif
try
{
#if WINDOWS_PHONE
var stream = ar.AsyncState as Stream;
var count = stream.EndRead(ar);
totalBytesRead = count + totalBytesRead;
#else
NetworkStream netStream = (NetworkStream)ar.AsyncState;
if (!netStream.CanRead)
throw new ObjectDisposedException("Unable to read from stream.");
totalBytesRead = netStream.EndRead(ar) + totalBytesRead;
dataAvailable = netStream.DataAvailable;
#endif
if (totalBytesRead > 0)
{
//收到數據後,更新連接信息類上的數據最後傳輸時間
ConnectionInfo.UpdateLastTrafficTime();
//If we have read a single byte which is 0 and we are not expecting other data
if (totalBytesRead == 1 && dataBuffer[0] == 0 && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == 0)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandler() from " + ConnectionInfo + ". 1");
}
else
{
//if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder.");
//If there is more data to get then add it to the packets lists;
//添加數據到“數據包創建器”(packetBuilder)中
packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);
#if !WINDOWS_PHONE
//If we have more data we might as well continue reading syncronously
//In order to deal with data as soon as we think we have sufficient we will leave this loop
//當接收到的數據小於數據包的大小的時候,循環接收
while (dataAvailable && packetBuilder.TotalBytesCached < packetBuilder.TotalBytesExpected)
{
int bufferOffset = 0;
//We need a buffer for our incoming data
//First we try to reuse a previous buffer
if (packetBuilder.TotalPartialPacketCount > 0 && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > 0)
dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref bufferOffset);
else
//If we have nothing to reuse we allocate a new buffer
dataBuffer = new byte[NetworkComms.ReceiveBufferSizeBytes];
//從數據流中接收數據
totalBytesRead = netStream.Read(dataBuffer, bufferOffset, dataBuffer.Length - bufferOffset) + bufferOffset;
if (totalBytesRead > 0)
{
ConnectionInfo.UpdateLastTrafficTime();
//If we have read a single byte which is 0 and we are not expecting other data
if (totalBytesRead == 1 && dataBuffer[0] == 0 && packetBuilder.TotalBytesExpected - packetBuilder.TotalBytesCached == 0)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandler() from " + ConnectionInfo + ". 2");
//LastTrafficTime = DateTime.Now;
}
else
{
//if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... " + totalBytesRead.ToString() + " bytes added to packetBuilder for connection with " + ConnectionInfo + ". Cached " + packetBuilder.TotalBytesCached.ToString() + "B, expecting " + packetBuilder.TotalBytesExpected.ToString() + "B.");
packetBuilder.AddPartialPacket(totalBytesRead, dataBuffer);
dataAvailable = netStream.DataAvailable;
}
}
else
break;
}
#endif
}
}
//如果接收到的數據足夠的多
if (packetBuilder.TotalBytesCached > 0 && packetBuilder.TotalBytesCached >= packetBuilder.TotalBytesExpected)
{
//Once we think we might have enough data we call the incoming packet handle handoff
//Should we have a complete packet this method will start the appriate task
//This method will now clear byes from the incoming packets if we have received something complete.
//調用IncomingPacketHandleHandOff方法處理“數據包接收器”(packetBuilder)中已經接收到的字節數據,並把二進制數據還原成相應的類型,進行處理
IncomingPacketHandleHandOff(packetBuilder);
}
if (totalBytesRead == 0 && (!dataAvailable || ConnectionInfo.ConnectionState == ConnectionState.Shutdown))
CloseConnection(false, -2);
else
{
//We need a buffer for our incoming data
//First we try to reuse a previous buffer
if (packetBuilder.TotalPartialPacketCount > 0 && packetBuilder.NumUnusedBytesMostRecentPartialPacket() > 0)
dataBuffer = packetBuilder.RemoveMostRecentPartialPacket(ref totalBytesRead);
else
{
//If we have nothing to reuse we allocate a new buffer
dataBuffer = new byte[NetworkComms.ReceiveBufferSizeBytes];
totalBytesRead = 0;
}
#if WINDOWS_PHONE
stream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, stream);
#else
//繼續接收TCP連接上的數據
netStream.BeginRead(dataBuffer, totalBytesRead, dataBuffer.Length - totalBytesRead, IncomingTCPPacketHandler, netStream);
#endif
}
}
catch (IOException)
{
CloseConnection(true, 12);
}
catch (ObjectDisposedException)
{
CloseConnection(true, 13);
}
catch (SocketException)
{
CloseConnection(true, 14);
}
catch (InvalidOperationException)
{
CloseConnection(true, 15);
}
catch (Exception ex)
{
NetworkComms.LogError(ex, "Error_TCPConnectionIncomingPacketHandler");
CloseConnection(true, 31);
}
#if !WINDOWS_PHONE
Thread.CurrentThread.Priority = ThreadPriority.Normal;
#endif
}
接收到的數據都交給PacketBuilder(數據包創建器)進行處理了,PacketBuilder如何對接收到的二進制數據進行處理,將在下一章進行分析。
www.cnblogs.com/networkcomms
www.networkcomms.cn