原文网址: 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. 翻译-DevOps究竟是什么?

    原文地址:http://www.drdobbs.com/architecture-and-design/what-exactly-is-devops/240009147 作者:Neil Garnich ...

  2. Windows 10 下安装 npm 后全局 node_modules 和 npm-cache 文件夹的设置

    npm 指 Node Package Manager,是 Node.js 中一个流行的包管理和分发工具.Node.js 在某个版本的 Windows 安装包开始已经加入了 npm,现在可以进入 htt ...

  3. Amazon Dynamo论文学习

    Dynamo是一个key-value数据存储系统,去中心化.高可扩展.高可用,使用一致性哈希来分区和备份数据,使用数据版本化来实现一致性. 核心技术 CAP:一致性.可用性.扩展性 一致性哈希:切分数 ...

  4. jdk研究——java.lang

    jdk研究 volatile 是什么意思? 如何看jdk源码? 如何调试源码!---------仔细解读关键类,关键代码,常用的api的解释! 自己有疑问的不懂地方-------- 不懂的太多怎么办. ...

  5. wep.py输出hello world

    webpy是python的一个简单的web开发的框架.可以通过简单的几行代码启动一个web服务(虽然只是输出helloworld). 准备工作 准备工具如下: 下载python[python开发环境] ...

  6. Lua标准库- 模块(Modules)

    Lua包库为lua提供简易的加载及创建模块的方法,由require.module方法及package表组成 1.module (name [, ···]) 功能:建立一个模块. module的处理流程 ...

  7. 了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发)

    了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发) Guillermo Rauch 编   赵静 译 ISBN 978-7-121-21769-2 2 ...

  8. Sublime Text配置Python开发利器

    Sublime Text配置Python开发利器 收好了 自动提示 jedi 代码格式化 Python PEP8 autoformat 如果还需要在shell中搞搞研究的话,ipython将是很好的选 ...

  9. Netty学习五:Buffers

    1. Netty中的缓冲 在Netty中并没有使用Java自带的ByteBuffer,而是自己实现提供了一个缓存区来用于标识一个字节序列,并帮助用户操作原始字节或者自定义的POJO. Java NIO ...

  10. 【WP 8.1开发】自定义(RAW)通知的使用

    继续前面的话题,还是推送通知.上一篇文章中遗留了RAW通知的推送没有给各位演示,特特地留到现在,不为别的,只为这个RAW通知有点意思,玩起来会比较有意思.官方文档将RAW通知译为“原始通知”,这里还是 ...