原文网址: http://www.cnblogs.com/csdev

Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是:Apache License v2

开源地址是:https://github.com/MarcFletcher/NetworkComms.Net

先来看一下数据包的接口类

/// <summary>
    /// Interface for defining Application Layer Protocol packets
    /// 数据包接口
    /// </summary>
    public interface IPacket
    {
        /// <summary>
        /// The packet header for this packet
        /// 数据包包头
        /// </summary>
        PacketHeader PacketHeader { get; }

        /// <summary>
        /// The payload data stream
        /// 数据包的数据部分
        /// </summary>
        StreamTools.StreamSendWrapper PacketData { get; }

        /// <summary>
        /// Returns the serialised bytes of the packet header appended by the serialised header size. This is required to
        /// rebuild the header on receive.
        /// 返回数据包包头被序列化后生成的二进制数据   这部分数据在被对方接收后将会用来重建数据包包头
        /// </summary>
        /// <returns>The serialised header as byte[]</returns>
        byte[] SerialiseHeader(SendReceiveOptions options);

        /// <summary>
        /// Dispose of internal packet resources
        /// 释放资源
        /// </summary>
        void Dispose();
    }
  /// <summary>
    /// Wrapper for <see cref="PacketHeader"/> and packetData.
    /// 数据包
    /// </summary>
    public class Packet : IDisposable, IPacket, IExplicitlySerialize
    {
        /// <summary>
        /// If we serialise a whole packet we include the packet header
        /// 数据包包头
        /// </summary>
        PacketHeader _packetHeader;

        /// <summary>
        /// And the payload object as byte[]. We cannot use type T here because we do not know the type of T
        /// on deserialisation until we have the nested packet header.
        /// 数据部分对应的二进制字节数组   我们不能使用T类型 因为我们在反序列化时不知道T的类型
        /// </summary>
        internal byte[] _payloadObjectBytes;
        internal int _payloadSize;

        StreamTools.StreamSendWrapper payloadStream;

        /// <summary>
        /// Parameterless constructor for deserialisation
        /// 反序列化时使用的无参数构造函数
        /// </summary>
        private Packet()
        {
        }

        /// <summary>
        /// Create a new packet
        /// 创建一个数据包
        /// </summary>
        /// <param name="sendingPacketTypeStr">发送的消息类型    The sending packet type</param>
        /// <param name="payloadObject">发送的对象     The object to be sent</param>
        /// <param name="options">收发参数    The <see cref="SendReceiveOptions"/> to be used to create this packet</param>
        public Packet(string sendingPacketTypeStr, object payloadObject, SendReceiveOptions options)
        {
            Constructor(sendingPacketTypeStr, null, payloadObject, options, false);
        }

        /// <summary>
        /// Create a new packet
        /// 创建一个数据包
        /// </summary>
        /// <param name="sendingPacketTypeStr">数据包的消息类型  The sending packet type</param>
        /// <param name="requestReturnPacketTypeStr">期待对方处理完成后返回的消息类型  The expected return packet type</param>
        /// <param name="payloadObject">发送的对象  The object to be sent</param>
        /// <param name="options">收发参数   The <see cref="SendReceiveOptions"/> to be used to create this packet</param>
        public Packet(string sendingPacketTypeStr, string requestReturnPacketTypeStr, object payloadObject, SendReceiveOptions options)
        {
            Constructor(sendingPacketTypeStr, requestReturnPacketTypeStr, payloadObject, options, false);
        }

        /// <summary>
        /// Private constructor used for nesting packets
        /// 私有的构造函数 用于发送嵌套数据包
        /// </summary>
        /// <param name="sendingPacketTypeStr"></param>
        /// <param name="requestReturnPacketTypeStr"></param>
        /// <param name="payloadObject"></param>
        /// <param name="options"></param>
        /// <param name="isNested"></param>
        private Packet(string sendingPacketTypeStr, string requestReturnPacketTypeStr, object payloadObject, SendReceiveOptions options, bool isNested)
        {
            Constructor(sendingPacketTypeStr, requestReturnPacketTypeStr, payloadObject, options, isNested);
        }

        private void Constructor<payloadObjectType>(string sendingPacketTypeStr, string requestReturnPacketTypeStr, payloadObjectType payloadObject, SendReceiveOptions options, bool isNested)
        {
            if (sendingPacketTypeStr == null || sendingPacketTypeStr == "") throw new ArgumentNullException("sendingPacketTypeStr", "The provided string can not be null or zero length.");
            if (options == null) throw new ArgumentNullException("options", "The provided SendReceiveOptions cannot be null.");
            if (options.DataSerializer == null) throw new ArgumentNullException("options", "The provided SendReceiveOptions.DataSerializer cannot be null. Consider using NullSerializer instead.");

            //Check for security critical data processors   检查安全关键数据处理器
            //There may be performance issues here  可能会有一点性能问题
            bool containsSecurityCritialDataProcessors = false;
            if (!options.Options.ContainsKey("UseNestedPacketType") && //We only need to perform this check if we are not already using a nested packet  我们只在没有使用嵌套数据包时执行检测
                !isNested) //We do not perform this check within a nested packet  在嵌套数据包中我们不执行检测
            {
                foreach (DataProcessor processor in options.DataProcessors)
                {
                    if (processor.IsSecurityCritical)
                    {
                        containsSecurityCritialDataProcessors = true;
                        break;
                    }
                }
            }

            //By default the object to serialise will be the payloadObject
            //默认  序列化的数据对象为 objectToSerialise
            object objectToSerialise = payloadObject;
            bool objectToSerialiseIsNull = false;

            //We only replace the null with an empty stream if this is either in the nested packet
            //or we will not be nesting
            //如果要发送的数据包内容为Null 并且当前数据包为嵌套数据包 或者选项中不包含"使用嵌套数据包类型"的数据包中,我们创建空数据流(emptyStream)代替NULL对象
            if (objectToSerialise == null &&
                ((!options.Options.ContainsKey("UseNestedPacketType") &&
                !containsSecurityCritialDataProcessors) || isNested))
            {
#if NETFX_CORE
                ], , , false);
#else
                ], , , false, true);
#endif
                //If the sending object is null we set objectToSerialiseIsNull and create a zero length StreamSendWrapper
                //The zero length StreamSendWrapper can then be passed to any data serializers
                //如果要发送的数据包内容为NULL,我们设置 objectToSerialiseIsNull属性为True.并且创建一个长度为0的StreamSendWrapper对象
               //这个长度为0的StreamSendWrapper对象可以传递给任何数据序列化器
                objectToSerialiseIsNull = true;
                objectToSerialise = new StreamTools.StreamSendWrapper(new StreamTools.ThreadSafeStream(emptyStream, true));
            }

            //If we need to nest this packet
            //如果我们需要嵌套数据包
            //嵌套数据包概念:
            //我的理解,把数据包中的数据部分包装成一个数据包
            //普通数据包 对方反序列化后得到实际的数据类型
            //嵌套数据包  对方反序列化得到Packet数据类型的数据  还要继续做解析
            if ((containsSecurityCritialDataProcessors || options.Options.ContainsKey("UseNestedPacketType")) && !isNested)
            {
                //We set the objectToSerialise to a nested packet
                //我们设置objectToSerialise对象为一个数据包
                objectToSerialise = new Packet(sendingPacketTypeStr, requestReturnPacketTypeStr, payloadObject, options, true);
            }
            else if (isNested)
            {
                //Serialise the payload object into byte[]
                //序列化数据包数据为字节数组
                //We do not use any data processors at this stage as the object will be processed again one level higher.
                //在此阶段 我们没有使用数据处理器
#if NETFX_CORE
                 _payloadObjectBytes = options.DataSerializer.SerialiseDataObject(payloadObject).ThreadSafeStream.ToArray();
                _payloadSize = _payloadObjectBytes.Length;
#else
                NetworkCommsDotNet.Tools.StreamTools.ThreadSafeStream tempStream = options.DataSerializer.SerialiseDataObject(objectToSerialise).ThreadSafeStream;
                _payloadObjectBytes = tempStream.GetBuffer();
                _payloadSize = (int)tempStream.Length;
#endif
                //Set the packet header
                //THe nulls represent internal SendReceiveOptions and no checksum
                //设置数据包包头
                //下面语句中的2个null参数代表使用 内部收发参数 和不使用检验和
                this._packetHeader = new PacketHeader(sendingPacketTypeStr, _payloadSize, null, requestReturnPacketTypeStr, null);

                //Set the deserialiser information in the nested packet header, excluding data processors
                //在嵌套数据包包头中设置反序列化相关信息 不包括数据处理器
                this._packetHeader.SetOption(PacketHeaderLongItems.SerializerProcessors, DPSManager.CreateSerializerDataProcessorIdentifier(options.DataSerializer, null));
            }

            //If we are at the top level packet we can finish off the serialisation
            //对于非嵌套类型的数据包 我们直接完成序列化
            if (!isNested)
            {
                //Set the payload stream data.
                //设置有效载荷数据流。
                )
                    //Only if there are no data processors can we use a zero length array for nulls
                    //This ensures that should there be any required padding we can include it
                    //如果没有数据处理器  options.DataProcessors.Count等于0
                    this.payloadStream = (StreamTools.StreamSendWrapper)objectToSerialise;
                else
                {
                    if (objectToSerialise is Packet)
                        //We have to use the internal explicit serializer for nested packets (the nested data is already byte[])
                        //针对嵌套数据 我们使用内部显式的序列化方法 嵌套的数据已经是字节数组
                        this.payloadStream = NetworkComms.InternalFixedSendReceiveOptions.DataSerializer.SerialiseDataObject(objectToSerialise, options.DataProcessors, options.Options);
                    else
                        this.payloadStream = options.DataSerializer.SerialiseDataObject(objectToSerialise, options.DataProcessors, options.Options);
                }

                //We only calculate the checkSum if we are going to use it
                //当需要使用时计算检验和
                string hashStr = null;
                if (NetworkComms.EnablePacketCheckSumValidation)
                    hashStr = StreamTools.MD5(payloadStream.ThreadSafeStream.ToArray(payloadStream.Start, payloadStream.Length));

                //Choose the sending and receiving packet type depending on if it is being used with a nested packet
                //如果为嵌套类型  则发送的数据包类型为"嵌套类型" 否则设定为实际的消息发送类型和消息接收类型
                string _sendingPacketTypeStr;
                string _requestReturnPacketTypeStr = null;
                if (containsSecurityCritialDataProcessors || options.Options.ContainsKey("UseNestedPacketType"))
                    _sendingPacketTypeStr = Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.NestedPacket);
                else
                {
                    _sendingPacketTypeStr = sendingPacketTypeStr;
                    _requestReturnPacketTypeStr = requestReturnPacketTypeStr;
                }

                this._packetHeader = new PacketHeader(_sendingPacketTypeStr, payloadStream.Length, options, _requestReturnPacketTypeStr, hashStr);

                //Add an identifier specifying the serialisers and processors we have used
                //在数据包包头中设定相应的"数据包序列化器和处理器"
                if (objectToSerialise is Packet)
                    this._packetHeader.SetOption(PacketHeaderLongItems.SerializerProcessors, DPSManager.CreateSerializerDataProcessorIdentifier(NetworkComms.InternalFixedSendReceiveOptions.DataSerializer, options.DataProcessors));
                else
                    this._packetHeader.SetOption(PacketHeaderLongItems.SerializerProcessors, DPSManager.CreateSerializerDataProcessorIdentifier(options.DataSerializer, options.DataProcessors));
            }

            //Set the null data header section if required
            //如果数据包数据为NULL 在包头部门标明
            if (objectToSerialiseIsNull &&
                ((!containsSecurityCritialDataProcessors && !options.Options.ContainsKey("UseNestedPacketType")) || isNested))
                this._packetHeader.SetOption(PacketHeaderStringItems.NullDataSection, "");

            if (NetworkComms.LoggingEnabled)
            {
                if (isNested)
                    NetworkComms.Logger.Trace(" ... created nested packet of type " + sendingPacketTypeStr);
                else
                    NetworkComms.Logger.Trace(" ... created packet of type " + sendingPacketTypeStr + ". PacketObject data size is " + payloadStream.Length.ToString() + " bytes");
            }
        }

        /// <inheritdoc />        ///数据包包头
        public PacketHeader PacketHeader
        {
            get { return _packetHeader; }
        }

        /// <inheritdoc />        //数据包的数据部分
        public StreamTools.StreamSendWrapper PacketData
        {
            get { return payloadStream; }
        }

        /// <inheritdoc />        //用于生成二级制的包头
        public byte[] SerialiseHeader(SendReceiveOptions options)
        {
            if (options == null) throw new ArgumentNullException("options", "Provided SendReceiveOptions cannot be null.");

            //We need to start of by serialising the header
            //把包头序列化为二进制数组
            byte[] serialisedHeader;
            using (StreamTools.StreamSendWrapper sendWrapper = options.DataSerializer.SerialiseDataObject(_packetHeader, options.DataProcessors, null))
                serialisedHeader = sendWrapper.ThreadSafeStream.ToArray();

             > byte.MaxValue)
                throw new SerialisationException("Unable to send packet as header size is larger than Byte.MaxValue. Try reducing the length of provided packetTypeStr or turning off checkSum validation.");

            //The first byte now specifies the header size (allows for variable header size)
            //包头转化成的二进制数据,第一个字节的值,设定为包头的长度
            serialisedHeader[] = ();

            if (serialisedHeader == null)
                throw new SerialisationException("Serialised header bytes should never be null.");

            return serialisedHeader;
        }

        /// <inheritdoc />
        public void Dispose()
        {
            payloadStream.Dispose();
        }

        #region IExplicitlySerialize Members

        /// <inheritdoc />        //序列化
        public void Serialize(Stream outputStream)
        {
            _packetHeader.Serialize(outputStream);
            outputStream.Write(BitConverter.GetBytes(_payloadSize), , sizeof(int));
            outputStream.Write(_payloadObjectBytes, , _payloadSize);
        }

        /// <inheritdoc />        //反序列化
        public void Deserialize(Stream inputStream)
        {
            PacketHeader.Deserialize(inputStream, out _packetHeader);

            byte[] payloadLengthData = new byte[sizeof(int)];
            inputStream.Read(payloadLengthData, , sizeof(int));

            _payloadSize = BitConverter.ToInt32(payloadLengthData, );
            _payloadObjectBytes = new byte[_payloadSize];
            inputStream.Read(_payloadObjectBytes, , _payloadSize);
        }

        #endregion

        /// <summary>
        /// Deserializes from a memory stream to a <see cref="Packet"/> object
        /// 把内存流反序列化为数据包
        /// </summary>
        /// <param name="inputStream">The memory stream containing the serialized <see cref="Packet"/></param>
        /// <param name="result">The deserialized <see cref="Packet"/></param>
        public static void Deserialize(Stream inputStream, out Packet result)
        {
            result = new Packet();
            result.Deserialize(inputStream);
        }
    }

介绍开源的.net通信框架NetworkComms框架 源码分析(四)Packet的更多相关文章

  1. DotNetty网络通信框架学习之源码分析

    DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...

  2. 深入理解分布式调度框架TBSchedule及源码分析

    简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...

  3. 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)

    1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...

  4. 设计模式(二十一)——解释器模式(Spring 框架中SpelExpressionParser源码分析)

    1 四则运算问题 通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输入表达式的形式,比如 a+b+c-d+e,  要求表达式的字母不能重复 2) 在分别输入 a ,b, c, ...

  5. $Django cbv源码分析 djangorestframework框架之APIView源码分析

    1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...

  6. ④NuPlayer播放框架之Renderer源码分析

    [时间:2016-11] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,渲染器,render] 0 导读 之前我们分析了NuPlayer的实现代码,本文将重点聚 ...

  7. ⑤NuPlayer播放框架之GenericSource源码分析

    [时间:2017-01] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,GenericSource] 0 导读 GenericSource是NuPlayer:: ...

  8. ③NuPlayer播放框架之类NuPlayer源码分析

    [时间:2016-10] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架] 0 引言 差不多一个月了,继续分析AOSP的播放框架的源码.这次我们需要深入分析的是N ...

  9. Laravel开发:Laravel框架门面Facade源码分析

    前言 这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facades(读音:/fəˈsäd/ )为应用程序的服务容器中可用的类提供了一个「静态」接口.Lara ...

  10. Android 应用框架层 SQLite 源码分析

    概述   Android 在应用框架层为开发者提供了 SQLite 相关操作接口,其归属于android.database.sqlite包底下,主要包含SQLiteProgram, SQLiteDat ...

随机推荐

  1. ECSHOP农行支付接口开发(含手机端)

    对于ECSHOP来说,支付是以接口的形式存在的.于是: 1:首先添加接口文件 includes\modules\payment下,增加abcbank.php,代码如下: <?php /** * ...

  2. asp.net mvc跨域filter

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  3. Redis教程(十一):虚拟内存介绍:

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/138.html 一.简介: 和大多NoSQL数据库一样,Redis同样遵循 ...

  4. lua如何构造类

    function class(super, autoConstructSuper) local classType = {}; classType.autoConstructSuper = autoC ...

  5. [Spring框架]Spring AOP基础入门总结一.

    前言:前面已经有两篇文章讲了Spring IOC/DI 以及 使用xml和注解两种方法开发的案例, 下面就来梳理一下Spring的另一核心AOP. 一, 什么是AOP 在软件业,AOP为Aspect ...

  6. Atitit. Atiposter 发帖机 新特性 poster new feature v11  .docx

    Atitit. Atiposter 发帖机 新特性 poster new feature v11  .docx 1.1.  版本历史1 2. 1. 未来版本规划2 2.1. V12版本规划2 2.2. ...

  7. salesforce 零基础开发入门学习(二)变量基础知识,集合,表达式,流程控制语句

    salesforce如果简单的说可以大概分成两个部分:Apex,VisualForce Page. 其中Apex语言和java很多的语法类似,今天总结的是一些简单的Apex的变量等知识. 有如下几种常 ...

  8. DOM_01之树及遍历

    1.DOM:ECMAScript+DOM+BOM,Document Object Model,核心DOM+HTML DOM+XML DOM: 2.辨析:①HTML:专门编写网页内容的语言:②XHTML ...

  9. IDE:Eclipse查看接口实现类快捷键

    1.打开接口类 2.双击接口名选中 3.Ctrl+T,打开接口实现类

  10. Android开发实践:编译VLC-for-android

    最近在Android做流媒体相关的开发,一直想学习一下强大的VLC,正好趁此机会研究研究VLC-for-android的代码,看看优秀的开源音视频播放器是如何实现的.本文总结下在Linux平台下如何编 ...