您的位置:首页 > 理论基础 > 计算机网络

c#网络通信框架networkcomms内核解析之五 数据监听

2015-02-14 21:59 465 查看
本文基于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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐