本文基于networkcomms2.3.1开源版本  gplv3协议

在networkcomms通信系统中,服务器端收到某连接上的数据后,数据会暂时存放在"数据包创建器"(PacketBuilder)中,PacketBuilder类似一个流动的容器,收到的数据被服务器处理完成后,相应在二进制数据,会从存储他的PacketBuilder中删除。

我们知道在networkcomms的消息体系中,传送的数据的第一个字节用来存储数据包包头长度,解析出数据包包头后,包头中包含数据包长度。所以在读入进入PacketBuilder中的数据,会根据第一个字节中存储的数据,解析出包头的长度,进一步解析出数据包的长度。如果PacketBuilder中的存储的字节大小,大于数据包的长度,那么主程序将会对PacketBuilder中的数据,进行提取,并进行处理。

此节,我们暂时不讨论PacketBuilder的细节,先看一下服务器如何对PacketBuilder中的数据进行处理

protected void IncomingPacketHandleHandOff(PacketBuilder packetBuilder)        {            try            {                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... checking for completed packet with " + packetBuilder.TotalBytesCached.ToString() + " bytes read.");                if (packetBuilder.TotalPartialPacketCount == 0)                    throw new Exception("Executing IncomingPacketHandleHandOff when no packets exist in packetbuilder.");                //循环,直到我们完成对packetBuilder的处理                //Loop until we are finished with this packetBuilder                int loopCounter = 0;                while (true)                {                    //If we have ended up with a null packet at the front, probably due to some form of concatentation 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字节数据                    if (packetBuilder.FirstByte() == 0)                    {                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandleHandOff() from " + ConnectionInfo + ", loop index - " + loopCounter.ToString());                        packetBuilder.ClearNTopBytes(1);                        //Reset the expected bytes to 0 so that the next check starts from scratch                        packetBuilder.TotalBytesExpected = 0;                        //If we have run out of data completely then we can return immediately                        if (packetBuilder.TotalBytesCached == 0) return;                    }                    else                    {                        //First determine the expected size of a header packet                        //获取数据包包头长度                        int packetHeaderSize = packetBuilder.FirstByte() + 1;                        //Do we have enough data to build a header?                        //如果没有足够的二级制数据来还原出一个数据包包头                        if (packetBuilder.TotalBytesCached < packetHeaderSize)                        {                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... ... more data required for complete packet header.");                            //Set the expected number of bytes and then return                            packetBuilder.TotalBytesExpected = packetHeaderSize;                            return;                        }                        //We have enough for a header                        //有足够的数据来还原出数据包包头                        PacketHeader topPacketHeader;                        using(MemoryStream headerStream = packetBuilder.ReadDataSection(1, packetHeaderSize - 1))                            //数据包包头                            topPacketHeader = new PacketHeader(headerStream, NetworkComms.InternalFixedSendReceiveOptions);                        //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                         //如果没有足够的数据来还原出数据包                        if (packetBuilder.TotalBytesCached < packetHeaderSize + topPacketHeader.PayloadPacketSize)                        {                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... ... more data required for complete packet payload. Expecting " + (packetHeaderSize + topPacketHeader.PayloadPacketSize).ToString() + " total packet bytes.");                            //Set the expected number of bytes and then return                            packetBuilder.TotalBytesExpected = packetHeaderSize + topPacketHeader.PayloadPacketSize;                            return;                        }                        //Second case is we have enough data                        //有足够的数据还原出数据包                        else if (packetBuilder.TotalBytesCached >= packetHeaderSize + topPacketHeader.PayloadPacketSize)                        {                            //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                            //no problem!!                            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.PayloadPacketSize.ToString() + " payload bytes.");                            //If this is a reserved packetType we call the method inline so that it gets dealt with immediately                            //判断是否为保留类型,保留类型会优先处理                            //保留类型包括心跳检测、连接建立等                            bool isReservedType = false;                            foreach (var tName in NetworkComms.reservedPacketTypeNames)                            {                                //isReservedType |= topPacketHeader.PacketType == tName;                                if (topPacketHeader.PacketType == tName)                                {                                    isReservedType = true;                                    break;                                }                            }                            //Only reserved packet types get completed inline                            //如果数据包类型为保留类型  设定为高优先级                            if (isReservedType)                            {#if WINDOWS_PHONE                                var priority = QueueItemPriority.Normal;#else                                var priority = (QueueItemPriority)Thread.CurrentThread.Priority;#endif                                //创建优先级队列项目                                PriorityQueueItem item = new PriorityQueueItem(priority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.PayloadPacketSize), incomingPacketSendReceiveOptions);                                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' inline. Loop index - " + loopCounter.ToString());                                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.PayloadPacketSize), incomingPacketSendReceiveOptions);                                //QueueItemPriority.Highest is the only priority that is executed inline#if !WINDOWS_PHONE                                //如果是最高优先级,当前线程处理                                if (itemPriority == QueueItemPriority.Highest)                                {                                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' with priority HIGHEST inline. Loop index - " + loopCounter.ToString());                                    NetworkComms.CompleteIncomingItemTask(item);                                }                                else                                {                                    //不是最高优先级 交给自定义线程池处理   此线程池支持优先级处理                                    int threadId = 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() + ", T:" + NetworkComms.CommsThreadPool.CurrentNumTotalThreads.ToString() + ", I:" + NetworkComms.CommsThreadPool.CurrentNumIdleThreads.ToString() + ") with priority " + itemPriority.ToString() + (threadId > 0 ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + ".");                                }#else                                int threadId = 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() + ", T:" + NetworkComms.CommsThreadPool.CurrentNumTotalThreads.ToString() + ", I:" + NetworkComms.CommsThreadPool.CurrentNumIdleThreads.ToString() + ") with priority " + itemPriority.ToString() + (threadId > 0 ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + ".");#endif                            }                            //从PacketBuilder中删除已经处理过的数据                            //We clear the bytes we have just handed off                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Removing " + (packetHeaderSize + topPacketHeader.PayloadPacketSize).ToString() + " bytes from incoming packet buffer from connection with " + ConnectionInfo +".");                            packetBuilder.ClearNTopBytes(packetHeaderSize + topPacketHeader.PayloadPacketSize);                            //Reset the expected bytes to 0 so that the next check starts from scratch                            packetBuilder.TotalBytesExpected = 0;                            //If we have run out of data completely then we can return immediately                            if (packetBuilder.TotalBytesCached == 0) return;                        }                        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 occured in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. See log file for more information.");                NetworkComms.LogError(ex, "CommsError");                CloseConnection(true, 45);            }        }

在上面的数据处理过程中,不知道您是否注意到一个重要的概念,即“自定义线程池”,

CommsThreadPool此线程池,可以说是Networkcomms通信框架中一颗璀璨的明珠,由他负责处理接收到的所有数据,此线程池支持优先级,即高优先级的数据会被优先处理www.networkcomms.cnwww.cnblogs.com/networkcomms

c#网络通信框架networkcomms内核解析之六 处理接收到的二进制数据的更多相关文章

  1. c#网络通信框架networkcomms内核解析 序言

    NetworkComms网络通信框架序言 networkcomms是我遇到的写的最优美的代码,很喜欢,推荐给大家:) 基于networkcomms2.3.1开源版本( gplv3)协议,写了一些文章, ...

  2. c#网络通信框架networkcomms内核解析之十 支持优先级的自定义线程池

    NetworkComms网络通信框架序言 本例基于networkcomms2.3.1开源版本  gplv3协议 如果networkcomms是一顶皇冠,那么CommsThreadPool(自定义线程池 ...

  3. c#网络通信框架networkcomms内核解析之八 数据包的核心处理器

    NetworkComms网络通信框架序言 本文基于networkcomms2.3.1开源版本  gplv3协议 我们先回顾一个 c#网络通信框架networkcomms内核解析之六 处理接收到的二进制 ...

  4. c#网络通信框架networkcomms内核解析之一 消息传送

    networkcomms.net 来自英国的网络通信框架 官方网址 www.networkcomms.net 中文网址www.networkcomms.cn 在网络通信程序中,本地的类或者对象,要传输 ...

  5. c#网络通信框架networkcomms内核解析之一 消息传送2

    networkcomms.net 来自英国的网络通信框架 官方网址 www.networkcomms.net 中文网址www.networkcomms.cn 在网络通信程序中,本地的类或者对象,要传输 ...

  6. c#网络通信框架networkcomms内核解析之三 消息同步调用

    networkcomms.net 来自英国的网络通信框架 官方网址 www.networkcomms.net 中文网址www.networkcomms.cn 客户端发送消息给服务器,服务器计算结果返回 ...

  7. c#网络通信框架networkcomms内核解析之九 自定义处理方法的运行机制

    NetworkComms网络通信框架序言 本文基于networkcomms2.3.1开源版本  gplv3协议 我们自己写的处理方法都称之为自定义处理方法 比如,我们在服务器上写的与登陆相关的处理方法 ...

  8. 介绍开源的.net通信框架NetworkComms框架 源码分析(十一)PacketBuilder

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...

  9. 介绍开源的.net通信框架NetworkComms框架 源码分析(三)PacketHeader

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...

随机推荐

  1. 【SpringBoot】 一种解决接口返回慢的方式

    前言 使用springboot开发后台代码的时候,很核心的一个功能是为前端提供接口,那么很可能你会遇到如下问题: 1. 接口里面调用的service层是第三方库或者第三方后台程序,导致访问很慢. 2. ...

  2. Ubuntu安装 docker

    安装docker首先要需要一台宿主机, 我目前用VMvare下安装的Ubuntu16.04系统为宿主机,进行docker安装测试. ubuntu安装时选的中文环境,生成的sources.list里面的 ...

  3. Python笔记(六)_函数

    函数一般是从第一行代码开始执行,结束于return语句.异常.或者函数所有语句执行完毕.一旦函数将控制权交还给调用者,就意味着全部结束.函数中做的所有工作以及保存在局部变量中的数据都将丢失.再次调用这 ...

  4. C语言|博客作业4

    一.本周教学内容:用C语言编写程序-循环结构 2.4 输出华氏-摄氏温度转换表.要求学生掌握使用for循环语句实现指定次数的循环程序设计. 二.本周作业头 问题 答案 这个作业属于哪个内容 C语言程序 ...

  5. Django ajax小例

    urls.py: url(r'^ajaxstudents/$', views.ajaxstudents), url(r'^getstudentsinfo/$', views.getstudentsin ...

  6. MSF——信息收集(四)

    MSF系列: MSF——基本使用和Exploit模块(一) MSF——Payload模块(二) MSF——Meterpreter(三) MSF——信息收集(四) 发现和端口扫描 Nmap扫描 db_n ...

  7. 洛谷 P1346 电车——dijstra

    上一波题目 https://www.luogu.org/problem/P1346 是道水题 路口一开始对着的那条路权值为0 其余路权值为1 然后跑一遍最短路就好了 qwq #include<c ...

  8. NOIP2015D1T2 信息传递

    题目描述 有 n 个同学(编号为 1 到 n )正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为 Ti​ 的同学. 游戏开始时,每人都只 ...

  9. 【记录】Mybatis Generator生成数据对象Date/TimeStamp 查询时间格式化

    Mybatis Generator是很好的工具帮助我们生成表映射关联代码,最近博主遇到一个问题,找了很久才解决, 就是用Mybatis Generator生成实体类的时候,Date 时间无法格式化输出 ...

  10. 【串线篇】SpringMVC运行流程

    1.所有请求,前端控制器(DispatcherServlet)收到请求,调用doDispatch进行处理 2.根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包 ...