原文网址: 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. linux下获取线程号

    #include <sys/syscall.h> pid_t gettid() { return syscall(SYS_gettid); }

  2. VC++中开发汇编语言(转)

    汇编程序结构 一个显示字符串的汇编程序 程序格式 一.模式定义 二.includelib语句 三.函数声明语句 四.数据和代码部分 Visual C/C++环境 建立工程 汇编程序的调试 一.设置断点 ...

  3. 程序员DNS知识指南

    本次内容比较hardcore,非科班出身可能会有理解障碍,可以考虑不用挣扎,直接放弃.毕竟普通驾驶员是不需要理解内燃机原理和曲轴如何做功的,所谓术业有专攻也,能看完的不是同行就是真爱~ 引 DNS对于 ...

  4. WebApi系列~自主宿主HttpSelfHost的实现

    回到目录 宿主一词我们不会陌生,它可以看作是一个基础设施,它为一些服务和功能提供最底层的支持,如你的web应用程序可以运行在iis或者apache上,而这两个东西就是web应用程序的宿主,而今天说的自 ...

  5. [Java工具]Java常用在线工具集合.

    转载申明: 转载自http://www.hollischuang.com/Grepcode SearchCode ProcessOn json.cn diffchecker MaHua .马克飞象 . ...

  6. salesforce 零基础学习(三十七) DML及Database方法简单描述

    在apex中通过soql查询可以使用两种方式,使用DML语句或者使用Database的方法. 使用DML语句和使用Database类的方法对于我们来说用的都很多,并且都很常见.对于数据库常见的操作:增 ...

  7. salesforce 零基础学习(二十二)Test简单使用

    本篇内容只是本人简单的mark开发中常出现的一些疑问,方便后期项目使用时奠定基础,如果对Test零基础童鞋,欢迎查看Test官方的使用介绍: https://help.salesforce.com/a ...

  8. ng-表单验证

    表单验证<AngularJs>   常用的表单验证指令 1. 必填项验证 某个表单输入是否已填写,只要在输入字段元素上添加HTML5标记required即可: <input type ...

  9. switch判断注意点

    if判断,如果判断的两个值类型不同,会继续隐性转换,==,当然如果使用===就不会. 1 if(2=="2"){ 2 console.log("true"); ...

  10. CSS选择器的浏览器支持

    CSS1 CSS2 CSS 3 :hover 在IE6中只有a元素可用. E:empty 貌似在webkit核心浏览器中有些小bug. 如果这个bug依然存在,不太确定如何测试. IE6不支持.cla ...