介绍开源的.net通信框架NetworkComms框架 源码分析(十九 )ConnectionIncomingData
原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
用于处理接收到的二级制数据,生成相关的数据包,并进一步进行解析
namespace NetworkCommsDotNet.Connections { public abstract partial class Connection { /// <summary> /// The <see cref="PacketBuilder"/> for this connection /// 数据包创建器 /// </summary> protected PacketBuilder packetBuilder; /// <summary> /// The total bytes read so far within dataBuffer /// 已经读取的数据长度 /// </summary> protected int totalBytesRead; #if !NETFX_CORE /// <summary> /// The thread listening for incoming data should we be using synchronous methods. /// 数据监听线程 /// </summary> protected Thread incomingDataListenThread = null; #endif /// <summary> /// True if async listen has started /// 是否为异步监听 /// </summary> protected bool asyncListenStarted = false; /// <summary> /// True if the async listen method is in a beginRead /// 是否为同步监听 /// </summary> protected volatile bool asyncListenerInRead = false; /// <summary> /// A connection specific method which triggers any requisites for accepting incoming data /// 开始监听传入的数据 /// </summary> protected abstract void StartIncomingDataListen(); /// <summary> /// Attempts to use the data provided in packetBuilder to recreate something useful. If we don't have enough data /// yet that value is set in packetBuilder. /// 处理"数据包创建器"(packetBuilder)中已经接收的二进制数据 /// </summary> /// <param name="packetBuilder">The <see cref="PacketBuilder"/> containing incoming cached data</param> protected void IncomingPacketHandleHandOff(PacketBuilder packetBuilder) { ; try { if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... checking for completed packet with " + packetBuilder.TotalBytesCached.ToString() + " bytes read."); ) throw new Exception("Executing IncomingPacketHandleHandOff when no packets exist in packetbuilder."); //Loop until we are finished with this packetBuilder //循环 直到我们完成对此packetBuilder上数据的处理 while (true) { //If we have ended up with a null packet at the front, probably due to some form of concatenation we can pull it off here //It is possible we have concatenation of several null packets along with real data so we loop until the firstByte is greater than 0 //如果收到的数据的第一个字节的内容是0 则一般为心跳检测消息 删除之就行 ) { #region Ignore Null Packet if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandleHandOff() from " + ConnectionInfo + ", loop index - " + loopCounter.ToString()); packetBuilder.ClearNTopBytes(); //Reset the expected bytes to 0 so that the next check starts from scratch //重新设置 期待的字节数 packetBuilder.TotalBytesExpected = ; //If we have run out of data completely then we can return immediately //如果packetBuilder中只有一个字节 没有更多的数据 则可以返回了 ) return; #endregion } else { ; PacketHeader topPacketHeader; #region Set topPacketHeader if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled) { //First determine the expected size of a header packet //数据包包头的长度 =第一个字节的内容 +1 (这个加1是加上第一个字节的长度) packetHeaderSize = packetBuilder.FirstByte() + ; //Do we have enough data to build a header? //如果我们没有足够的数据来创建数据包包头 if (packetBuilder.TotalBytesCached < packetHeaderSize) { if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... require " + packetHeaderSize + " bytes for packet header, only " + packetBuilder.TotalBytesCached + " bytes cached."); //Set the expected number of bytes and then return // 设定packetBuilder中期待的数据位数据包包头的大小 packetBuilder.TotalBytesExpected = packetHeaderSize; return; } if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... deserializing header using " + packetHeaderSize + " bytes, " + packetBuilder.TotalBytesCached + " bytes cached."); //We have enough for a header //有足够的数据 解析出数据包包头 , packetHeaderSize - )) topPacketHeader = new PacketHeader(headerStream, NetworkComms.InternalFixedSendReceiveOptions); } else topPacketHeader = new PacketHeader(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged), packetBuilder.TotalBytesCached); #endregion //Idiot test if (topPacketHeader.PacketType == null) throw new SerialisationException("packetType value in packetHeader should never be null"); //We can now use the header to establish if we have enough payload data //First case is when we have not yet received enough data //如果packetBuilder中已经接收的数据 小于 (包头的长度+数据包的长度) if (packetBuilder.TotalBytesCached < packetHeaderSize + topPacketHeader.TotalPayloadSize) { if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... more data required for complete packet payload. Expecting " + (packetHeaderSize + topPacketHeader.TotalPayloadSize).ToString() + " total packet bytes."); //Set the expected number of bytes and then return //设定packetBuilder中期待的字节数 packetBuilder.TotalBytesExpected = packetHeaderSize + topPacketHeader.TotalPayloadSize; return; } //Second case is we have enough data //此处 我们已经有足够的数据解析出数据包 else if (packetBuilder.TotalBytesCached >= packetHeaderSize + topPacketHeader.TotalPayloadSize) { #region Handle Packet //We can either have exactly the right amount or even more than we were expecting //We may have too much data if we are sending high quantities and the packets have been concatenated //packetBuilder中已经接收的数据,可能比我们预期的数据还要多 这没有关系 我们先处理当期数据包所属的数据 SendReceiveOptions incomingPacketSendReceiveOptions = IncomingPacketSendReceiveOptions(topPacketHeader); if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Received packet of type '" + topPacketHeader.PacketType + "' from " + ConnectionInfo + ", containing " + packetHeaderSize.ToString() + " header bytes and " + topPacketHeader.TotalPayloadSize.ToString() + " payload bytes."); bool isReservedPacketType = (topPacketHeader.PacketType != Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged) && NetworkComms.ReservedPacketTypeNames.ContainsKey(topPacketHeader.PacketType)); //Get the packet sequence number if logging //获取数据包的顺序号 string packetSeqNumStr = ""; if (NetworkComms.LoggingEnabled) packetSeqNumStr = (topPacketHeader.ContainsOption(PacketHeaderLongItems.PacketSequenceNumber) ? ". pSeq#-" + topPacketHeader.GetOption(PacketHeaderLongItems.PacketSequenceNumber).ToString() + "." : ""); //Only reserved packet types get completed inline by default //如果数据包为通信框架保留类型 在当前线程直接处理 if (isReservedPacketType) { #if WINDOWS_PHONE || NETFX_CORE QueueItemPriority priority = QueueItemPriority.Normal; #else QueueItemPriority priority = (QueueItemPriority)Thread.CurrentThread.Priority; #endif PriorityQueueItem item = new PriorityQueueItem(priority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.TotalPayloadSize), incomingPacketSendReceiveOptions); if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr); NetworkComms.CompleteIncomingItemTask(item); } else { QueueItemPriority itemPriority = (incomingPacketSendReceiveOptions.Options.ContainsKey("ReceiveHandlePriority") ? (QueueItemPriority)Enum.Parse(typeof(QueueItemPriority), incomingPacketSendReceiveOptions.Options["ReceiveHandlePriority"]) : QueueItemPriority.Normal); PriorityQueueItem item = new PriorityQueueItem(itemPriority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.TotalPayloadSize), incomingPacketSendReceiveOptions); //QueueItemPriority.Highest is the only priority that is executed inline //只有优先级为最高级的数据包 在当前线程进行处理 if (itemPriority == QueueItemPriority.Highest) { if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' with priority HIGHEST inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr); NetworkComms.CompleteIncomingItemTask(item); } else { #if NETFX_CORE NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item); if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ") with priority " + itemPriority.ToString() + ". Loop index=" + loopCounter.ToString() + packetSeqNumStr); #else int threadId = NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item); ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + packetSeqNumStr); #endif } } //We clear the bytes we have just handed off //从packetBuilder中删除我们已经处理过的数据 if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Removing " + (packetHeaderSize + topPacketHeader.TotalPayloadSize).ToString() + " bytes from incoming packet builder from connection with " + ConnectionInfo +"."); packetBuilder.ClearNTopBytes(packetHeaderSize + topPacketHeader.TotalPayloadSize); //Reset the expected bytes to 0 so that the next check starts from scratch //重置 packetBuilder期待的数据为0 packetBuilder.TotalBytesExpected = ; //If we have run out of data completely then we can return immediately //如果packetBuilder中没有更多的数据需要处理 返回即可 ) return; #endregion } else throw new CommunicationException("This should be impossible!"); } loopCounter++; } } catch (Exception ex) { //Any error, throw an exception.错误 抛出异常 if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Fatal("A fatal exception occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. See log file for more information."); if (this is IPConnection) { //Log the exception in DOS protection if enabled 如果启用了DOS攻击防御 进行相关记录 if (IPConnection.DOSProtection.Enabled && ConnectionInfo.RemoteEndPoint.GetType() == typeof(IPEndPoint)) IPConnection.DOSProtection.LogMalformedData(ConnectionInfo.RemoteIPEndPoint.Address); } LogTools.LogException(ex, "CommsError", "A fatal exception occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. Loop counter " + loopCounter.ToString() + ". Packet builder contained " + packetBuilder.TotalBytesCached + " total cached bytes."); CloseConnection(); } } /// <summary> /// Handle an incoming CheckSumFailResend packet type /// 处理检测和失败需要重发的数据 /// </summary> /// <param name="packetDataSection"></param> internal void CheckSumFailResendHandler(MemoryStream packetDataSection) { //If we have been asked to resend a packet then we just go through the list and resend it. //如果我们被要求重新发送数据包 我们就通过列表重发相关数据。 SentPacket packetToReSend; lock (sentPacketsLocker) { string checkSumRequested = NetworkComms.InternalFixedSendReceiveOptions.DataSerializer.DeserialiseDataObject<string>(packetDataSection, NetworkComms.InternalFixedSendReceiveOptions.DataProcessors, NetworkComms.InternalFixedSendReceiveOptions.Options); if (sentPackets.ContainsKey(checkSumRequested)) packetToReSend = sentPackets[checkSumRequested]; else throw new CheckSumException("There was no packet sent with a matching check sum"); } //If we have already tried resending the packet 10 times something has gone horribly wrong //如果重发超过10此 抛出异常 ) throw new CheckSumException("Packet sent resulted in a catastrophic checksum check exception."); if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Warn(" ... resending packet due to MD5 mismatch."); //Increment send count and then resend //增加重发的次数 并进行重发 packetToReSend.IncrementSendCount(); SendPacket<object>(packetToReSend.Packet); } } }
介绍开源的.net通信框架NetworkComms框架 源码分析(十九 )ConnectionIncomingData的更多相关文章
- DotNetty网络通信框架学习之源码分析
DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...
- 深入理解分布式调度框架TBSchedule及源码分析
简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...
- 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)
1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...
- 设计模式(二十一)——解释器模式(Spring 框架中SpelExpressionParser源码分析)
1 四则运算问题 通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输入表达式的形式,比如 a+b+c-d+e, 要求表达式的字母不能重复 2) 在分别输入 a ,b, c, ...
- $Django cbv源码分析 djangorestframework框架之APIView源码分析
1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...
- ④NuPlayer播放框架之Renderer源码分析
[时间:2016-11] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,渲染器,render] 0 导读 之前我们分析了NuPlayer的实现代码,本文将重点聚 ...
- ⑤NuPlayer播放框架之GenericSource源码分析
[时间:2017-01] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,GenericSource] 0 导读 GenericSource是NuPlayer:: ...
- ③NuPlayer播放框架之类NuPlayer源码分析
[时间:2016-10] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架] 0 引言 差不多一个月了,继续分析AOSP的播放框架的源码.这次我们需要深入分析的是N ...
- Laravel开发:Laravel框架门面Facade源码分析
前言 这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facades(读音:/fəˈsäd/ )为应用程序的服务容器中可用的类提供了一个「静态」接口.Lara ...
- Android 应用框架层 SQLite 源码分析
概述 Android 在应用框架层为开发者提供了 SQLite 相关操作接口,其归属于android.database.sqlite包底下,主要包含SQLiteProgram, SQLiteDat ...
随机推荐
- IOS 公共类-数字处理
1.写一个方法,调用的时候交换两个数的值 -(void) swap:(int*)a andNumber:(int*)b{ int temp = *a; *a = *b; *b = temp; } 调用 ...
- NodeJS系列~第一个小例子,实现了request.querystring功能
返回目录 百度百科上: Node.js是一套用来编写高性能网络服务器的JavaScript工具包,一系列的变化由此开始,在Node中,Http是首要的.Node为创建http服务器作了优化,所以在网上 ...
- Atitti 知识图谱构建方法attilax 总结
Atitti 知识图谱构建方法attilax 总结 1.1. 知识图谱schema构建(体系化)1 1.2. 纵向垂直拓展(向上抽象,向下属性拓展)2 1.3. 横向拓展2 1.4. 网拓展2 1 ...
- C#教程(1) -- .Net与C#简介
(1).Net .Net指.Net平台或者是.Net Framework框架. 如果你把.Net平台想象成一个厨房,那么.Net Framework框架就是其中的柴米油盐酱醋茶. 如果你把.Net平台 ...
- css3使用box-sizing布局
css3增添了盒模型box-sizing,属性值有下面三个: content-box:默认值,让元素维持W3C的标准盒模型.元素的宽度/高度(width/height)(所占空间)等于元素边框宽度(b ...
- 关于BUG率的计算和它的实际意义的思考
我的微信号是Shalayang,以下是我的二维码名片,欢迎添加. 问题1:bug率有什么作用? my opion:用处有很多,需要具体情况具体分析,不过主要作用一般是来评价工作产品的质量.如果bug率 ...
- Java中的数是用补码表示的检验
一.基本介绍(关于下列五个定义来自http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html#!comments,谢原 ...
- java8--stream
*:first-child { margin-top: 0 !important; } .markdown-body>*:last-child { margin-bottom: 0 !impor ...
- javascript运算符——位运算符
× 目录 [1]二进制 [2]非 [3]与[4]或[5]异或[6]左移[7]右移[8]>>>[9]应用 前面的话 位运算符是非常底层的运算,由于其很不直观,所以并不常用.但是,其速度 ...
- hdu4292Food(最大流Dinic算法)
/* 题意:每一个人都有喜欢的吃的和喝的,每一个人只选择一个数量的吃的和一个数量的喝的,问能满足最多的人数!? 思路:建图很是重要!f-food, p-people, d-drink 建图: 0(源点 ...