介绍开源的.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 ...
 
随机推荐
- 【译】用jQuery 处理XML--浏览器中的XML与JavaScript
			
用jQuery 处理XML--写在前面的话 用jQuery 处理XML-- DOM(文本对象模型)简介 用jQuery 处理XML--浏览器中的XML与JavaScript 用jQuery 处理XML ...
 - MVVM架构~knockoutjs系列之正则表达式使规则更灵活
			
返回目录 几乎每种验证架构都会有正则表达式的加盟,一般地,一种验证架构首先会提供一些标准的,常用的验证规则,它们通常是数字验证,电话验证,email验证,长度验证,范围验证,日期验证等,而如果使你的验 ...
 - JavaScript模板引擎实例应用
			
在之前的一篇名为<移动端基于HTML模板和JSON数据的JavaScript交互>的文章中,我向大家说明了为什么要使用JavaScript模板以及如何使用,文末还提到了laytpl.art ...
 - fir.im Weekly - 你与优秀源码之间只差一个 Star
			
说起开源社区,Github 是一个不可缺少的存在.作为全球最大的同性交友网站,上面有太多优秀的开源代码库和编程大神,让无数开发者心生向往.那么如何正确的使用 Github,也许是编程学习之必要.来看下 ...
 - 安卓学习进程(2)Android开发环境的搭建
			
本节将分为五个步骤来完成Android开发环境的部署. 第一步:安装JDK. 第二步:配置Windows上JDK的变量环境 . 第三步:下载安装Eclipse . 第四步:下载安装Androi ...
 - HTML网页内容转换成字符串(删除从指定字符串到指定字符串)
			
背景: 最近遇到个小需求就是将下面字符串去掉无用字符串 <br><br>"你爷爷也喜欢吃鱼嘛."<br><br>我笑了起来,&quo ...
 - Visual-Studio-2015-Cheat-Sheet  Visual Studio 2015 快捷键列表
			
PDF 文件下载 http://files.cnblogs.com/files/JamesLi2015/Visual-Studio-2015-Cheat-Sheet.pdf
 - ASP.NET MVC中使用FluentValidation验证实体
			
1.FluentValidation介绍 FluentValidation是与ASP.NET DataAnnotataion Attribute验证实体不同的数据验证组件,提供了将实体与验证分离开来的 ...
 - Topology Shapes of OpenCascade BRep
			
Topology Shapes of OpenCascade BRep eryar@163.com 摘要Abstract:通过对OpenCascade中的BRep数据的读写,理解边界表示法的概念及实现 ...
 - 云计算之路-阿里云上:Web服务器遭遇奇怪的“黑色30秒”问题
			
今天下午访问高峰的时候,主站的Web服务器出现奇怪的问题,开始是2台8核8G的云服务器(ECS),后来又加了1台8核8G的云服务器,问题依旧. 而且3台服务器特地使用了不同的配置:1台是禁用了虚拟内存 ...