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

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

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

PacketHeader 数据包头

这个类,就是数据包的包头部分,在使用networkcomms通信框架时,发送数据时,框架会首先把数据转化成数据包(Packet).数据包包含(PacketHeader+包体部分)

首先来看2个枚举类

数据包包头中,Long类型的项.包括数据包包体部分的大小TotalPayloadSize,

序列化处理器 SerializerProcessors,包的顺序号PacketSequenceNumber,包的创建时间PacketCreationTime

  /// <summary>
    /// Any <see cref="PacketHeader"/> options which are stored as a long.
    /// 数据包包头的一些参数选项 Long类型
    /// </summary>
    public enum PacketHeaderLongItems
    {
        /// <summary>
        /// The total size of the packet data payload in bytes. This is a compulsory option.
        /// 数据包大小 此项为必需项目
        /// </summary>
        TotalPayloadSize,

        /// <summary>
        /// The data serialiser and data processor used to unwrap the payload. Used as flags.
        /// 数据序列化器和处理器相对应的值
        /// 这里解释一下 每个序列化器和处理器都对应一个值  通过计算合成此项参数 通过此项参数也能分析出使用了哪些序列化器和处理器
        /// </summary>
        SerializerProcessors,

        /// <summary>
        /// The sequence number for this packet. Each connection maintains a unique counter which is increments on each sent packet. This is a compulsory option.
        /// 顺序号   每个连接维护一个单独的计数器 此顺序号每次发送数据包后都自增长  也就是每个数据包都有一个唯一的顺序号  此项为必需项目
        /// </summary>
        PacketSequenceNumber,

        /// <summary>
        /// The creation time of the packet header.
        /// 数据包包头创建时间
        /// </summary>
        PacketCreationTime,
    }

包头中字符类型的项

数据包的消息类型  PacketType

对方收到消息后,是否需要回复 ReceiveConfirmationRequired

如果需要回复类型   RequestedReturnPacketType

数据包对应的检验和 CheckSumHash

SourceNetworkIdentifier  网络ID  每个连接是唯一的

  /// <summary>
    /// Any <see cref="PacketHeader"/> options which are stored as a string.
    /// 数据包包头参数 字符类型
    /// </summary>
    public enum PacketHeaderStringItems
    {
        /// <summary>
        /// The type of the packet. This is a compulsory option which determines how the incoming packet is handled.
        /// 数据包的消息类型  此项为必需项目    对方根据数据包的消息类型选择相对应的处理器
        /// </summary>
        PacketType,

        /// <summary>
        /// Specifies if a receive confirmation is required for this packet. String option as takes up less space for a boolean option.
        /// 对方收到后,是否需要发送确认消息  字符串选项占用更少的空间
        /// </summary>
        ReceiveConfirmationRequired,

        /// <summary>
        /// The packet type which should be used for any return packet type.
        /// 如果发送的是同步消息,即需要接收对方返回的结果   指定预期返回的消息类型
        /// </summary>
        RequestedReturnPacketType,

        /// <summary>
        /// A checksum corresponding to the payload data.
        /// 数据包对应的检验和
        /// </summary>
        CheckSumHash,

        /// <summary>
        /// The network identifier of the packet source
        /// 网络ID
        /// </summary>
        SourceNetworkIdentifier,

        /// <summary>
        /// Optional packet identifier.
        /// 数据包ID 可选
        /// </summary>
        PacketIdentifier,

        /// <summary>
        /// The data section should be interpreted as a null
        /// 数据包为Null
        /// </summary>
        NullDataSection,
    }

数据包包头 PacketHeader

/// <summary>
    /// Contains information required to send, receive and correctly rebuild any objects sent via NetworkComms.Net.
    /// Any data sent via NetworkCommsDotNet is always preceded by a packetHeader.
    /// 数据包包头  包含发送,接收,重建二进制数据为数据包的相关信息
    /// 通过networkcomms框架发送的数据,总是先发送数据包包头,再发送数据包
    /// 数据包包头的第一个字节,存储数据包包头的长度
    /// </summary>
    public sealed class PacketHeader : IExplicitlySerialize
    {
        Dictionary<PacketHeaderLongItems, long> longItems;
        Dictionary<PacketHeaderStringItems, string> stringItems;

        /// <summary>
        /// Blank constructor required for deserialisation
        /// 构造函数  反序列化时使用
        /// </summary>
#if ANDROID || iOS
        [Preserve]
#endif
        private PacketHeader() { }

        /// <summary>
        /// Creates a new packetHeader
        /// 创建一个新的数据包包头
        /// </summary>
        /// <param name="packetTypeStr">数据包的消息类型  The packet type to be used.</param>
        /// <param name="payloadPacketSize">数据包的大小  The size on bytes of the payload</param>
        /// <param name="sendReceiveOptions">收发参数 Send receive options which may contain header relevant options.</param>
        /// <param name="requestedReturnPacketTypeStr">返回的消息类型  An optional field representing the expected return packet type</param>
        /// <param name="checkSumHash">检验和  An optional field representing the payload checksum</param>
        public PacketHeader(string packetTypeStr, long payloadPacketSize, SendReceiveOptions sendReceiveOptions = null, string requestedReturnPacketTypeStr = null, string checkSumHash = null)
        {
            if (packetTypeStr == requestedReturnPacketTypeStr)
                throw new ArgumentException("The provided packetTypeStr and requestedReturnPacketTypeStr parameters must be different.");

            longItems = new Dictionary<PacketHeaderLongItems, long>();
            stringItems = new Dictionary<PacketHeaderStringItems, string>();

            stringItems.Add(PacketHeaderStringItems.PacketType, packetTypeStr);
            longItems.Add(PacketHeaderLongItems.TotalPayloadSize, payloadPacketSize);

            )
                throw new Exception("payloadPacketSize can not be less than 0.");

            if (requestedReturnPacketTypeStr != null)
                stringItems.Add(PacketHeaderStringItems.RequestedReturnPacketType, requestedReturnPacketTypeStr);

            if (checkSumHash != null)
                stringItems.Add(PacketHeaderStringItems.CheckSumHash, checkSumHash);

            if (sendReceiveOptions != null)
            {
                if (sendReceiveOptions.Options.ContainsKey("ReceiveConfirmationRequired"))
                    stringItems.Add(PacketHeaderStringItems.ReceiveConfirmationRequired, "");

                if (sendReceiveOptions.Options.ContainsKey("IncludePacketConstructionTime"))
                    longItems.Add(PacketHeaderLongItems.PacketCreationTime, DateTime.Now.Ticks);
            }
        }

        /// <summary>
        /// Constructor used for deserialisation
        /// 用于反序列化的构造函数
        /// </summary>
        /// <param name="packetHeaderStream"></param>
        /// <param name="headerSendReceiveOptions"></param>
        internal PacketHeader(MemoryStream packetHeaderStream, SendReceiveOptions headerSendReceiveOptions)
        {
            try
            {
                if (packetHeaderStream == null) throw new ArgumentNullException("packetData", "Provided MemoryStream parameter cannot be null.");
                if (headerSendReceiveOptions == null) throw new ArgumentNullException("sendReceiveOptions", "Provided SendReceiveOptions parameter cannot be null.");

                )
                    throw new SerialisationException("Attempted to create packetHeader using byte[0].");

                PacketHeader tempObject = headerSendReceiveOptions.DataSerializer.DeserialiseDataObject<PacketHeader>(packetHeaderStream, headerSendReceiveOptions.DataProcessors, headerSendReceiveOptions.Options);
                if (tempObject == null || !tempObject.longItems.ContainsKey(PacketHeaderLongItems.TotalPayloadSize) || !tempObject.stringItems.ContainsKey(PacketHeaderStringItems.PacketType))
                    throw new SerialisationException("Failed to deserialize a valid packet header. Deserialized header result was null or did not contain the compulsory fields, TotalPayloadSize and PacketType.");
                else
                {
                    stringItems = new Dictionary<PacketHeaderStringItems, string>();
                    foreach (var pair in tempObject.stringItems)
                        stringItems.Add(pair.Key, pair.Value);

                    longItems = new Dictionary<PacketHeaderLongItems, long>();
                    foreach (var pair in tempObject.longItems)
                        longItems.Add(pair.Key, pair.Value);
                }
            }
            catch (Exception ex)
            {
                NetworkCommsDotNet.Tools.LogTools.LogException(ex, "PacketHeaderDeserialisationError", "The header data follows:" + BitConverter.ToString(packetHeaderStream.ToArray()));
                throw new SerialisationException("Error deserializing packetHeader. " + ex.ToString());
            }
        }

        #region Get & Set
        /// <summary>
        /// The total size in bytes of the payload.
        /// 数据包的大小
        /// </summary>
        public int TotalPayloadSize
        {
            get { return (int)longItems[PacketHeaderLongItems.TotalPayloadSize]; }
        }

        /// <summary>
        /// The packet type.
        /// 数据包的类型
        /// </summary>
        public string PacketType
        {
            get { return stringItems[PacketHeaderStringItems.PacketType]; }
        }

        /// <summary>
        /// The sequence number for this packet
        /// 数据包的顺序号
        /// </summary>
        public long PacketSequenceNumber
        {
            get { return longItems[PacketHeaderLongItems.PacketSequenceNumber]; }
        }

        /// <summary>
        /// The packet type which should be used for any return packet type. If no return packet type is set returns null.
        /// 数据包被处理后,返回的消息类型
        /// 主要用于同步方法
        /// </summary>
        public string RequestedReturnPacketType
        {
            get
            {
                if (stringItems.ContainsKey(PacketHeaderStringItems.RequestedReturnPacketType))
                    return stringItems[PacketHeaderStringItems.RequestedReturnPacketType];
                else
                    return null;
            }
        }

        /// <summary>
        /// Optional packet identifier. If no packet identifier is set returns null.
        /// 数据包ID  可选   如果没有数据包ID ,返回NULL
        /// </summary>
        public string PacketIdentifier
        {
            get
            {
                if (stringItems.ContainsKey(PacketHeaderStringItems.PacketIdentifier))
                    return stringItems[PacketHeaderStringItems.PacketIdentifier];
                else
                    return null;
            }
        }

        /// <summary>
        /// The network identifier of the packets source peer. If no source network identifier is set returns null.
        /// Also see <see cref="ConnectionInfo.NetworkIdentifier"/>.
        /// 网络ID   如果没有返回NULL
        /// </summary>
        public string SourceNetworkIdentifier
        {
            get
            {
                if (stringItems.ContainsKey(PacketHeaderStringItems.SourceNetworkIdentifier))
                    return stringItems[PacketHeaderStringItems.SourceNetworkIdentifier];
                else
                    return null;
            }
        }

        /// <summary>
        /// A checksum corresponding to the payload data. If no checksum is set returns null.
        /// 数据包的检验和
        /// </summary>
        public string CheckSumHash
        {
            get
            {
                if (stringItems.ContainsKey(PacketHeaderStringItems.CheckSumHash))
                    return stringItems[PacketHeaderStringItems.CheckSumHash];
                else
                    return null;
            }
        }

        /// <summary>
        /// Check if a string option has been set.
        /// 检查某个字符型选项是否存在
        /// </summary>
        /// <param name="option">The string option to be checked.</param>
        /// <returns>Returns true if the provided string option has been set.</returns>
        public bool ContainsOption(PacketHeaderStringItems option)
        {
            return stringItems.ContainsKey(option);
        }

        /// <summary>
        /// Check if a long option has been set.
        /// 检查某个long类型选项是否存在
        /// </summary>
        /// <param name="option">The long option to be checked.</param>
        /// <returns>Returns true if the provided long option has been set.</returns>
        public bool ContainsOption(PacketHeaderLongItems option)
        {
            return longItems.ContainsKey(option);
        }

        /// <summary>
        /// Get a long option.
        /// 获取一个long类型选项
        /// </summary>
        /// <param name="option">The option to get</param>
        /// <returns>The requested long option</returns>
        public long GetOption(PacketHeaderLongItems option)
        {
            return longItems[option];
        }

        /// <summary>
        /// Get a string option
        /// 获取一个字符型选项
        /// </summary>
        /// <param name="options">The option to get</param>
        /// <returns>The requested string option</returns>
        public string GetOption(PacketHeaderStringItems options)
        {
            return stringItems[options];
        }

        /// <summary>
        /// Set a long option with the provided value.
        /// 设置一个long类型选项
        /// </summary>
        /// <param name="option">The option to set</param>
        /// <param name="Value">The option value</param>
        public void SetOption(PacketHeaderLongItems option, long Value)
        {
            longItems[option] = Value;
        }

        /// <summary>
        /// Set a string option with the provided value.
        /// 设置一个字符型选项
        /// </summary>
        /// <param name="option">The option to set</param>
        /// <param name="Value">The option value</param>
        public void SetOption(PacketHeaderStringItems option, string Value)
        {
            stringItems[option] = Value;
        }
        #endregion

        // V3版本中通讯框架内部没有采用V2版本中使用的protobuf.net序列化方法,使得程序应用层可以很方便的更换序列化器
        #region IExplicitlySerialize Members

        /// <inheritdoc />
        public void Serialize(Stream outputStream)
        {
            List<byte[]> data = new List<byte[]>();

            byte[] longItemsLengthData = BitConverter.GetBytes(longItems.Count); data.Add(longItemsLengthData);

            foreach (var pair in longItems)
            {
                byte[] keyData = BitConverter.GetBytes((int)pair.Key); data.Add(keyData);
                byte[] valData = BitConverter.GetBytes(pair.Value); data.Add(valData);
            }

            byte[] stringItemsLengthData = BitConverter.GetBytes(stringItems.Count); data.Add(stringItemsLengthData);

            foreach (var pair in stringItems)
            {
                byte[] keyData = BitConverter.GetBytes((int)pair.Key); data.Add(keyData);
                byte[] valData = Encoding.UTF8.GetBytes(pair.Value);
                byte[] valLengthData = BitConverter.GetBytes(valData.Length);

                data.Add(valLengthData);
                data.Add(valData);
            }

            foreach (byte[] datum in data)
                outputStream.Write(datum, , datum.Length);
        }

        /// <inheritdoc />
        public void Deserialize(Stream inputStream)
        {
            longItems = new Dictionary<PacketHeaderLongItems, long>();
            stringItems = new Dictionary<PacketHeaderStringItems, string>();

            , sizeof(int));
            );

            if (longItemsLength * (sizeof(int) + sizeof(long)) > inputStream.Length)
                throw new SerialisationException("Error deserializing packet header. Number of long items was too large to be present in the input stream."+
                    " This error is typically thrown because a non NetworkComms.Net peer attempted to communicate. If this is desirable please consider using an unmanaged connection.");

            ; i < longItemsLength; i++)
            {
                , sizeof(int));
                PacketHeaderLongItems key = (PacketHeaderLongItems)BitConverter.ToInt32(keyData, );

                , sizeof(long));
                );

                longItems.Add(key, val);
            }

            , sizeof(int));
            );

             * sizeof(int)) > inputStream.Length)
                throw new SerialisationException("Error deserializing packet header. Number of string items was too large to be present in the input stream."+
                    " This error is typically thrown because a non NetworkComms.Net peer attempted to communicate. If this is desirable please consider using an unmanaged connection.");

            ; i < stringItemsLength; i++)
            {
                , sizeof(int));
                PacketHeaderStringItems key = (PacketHeaderStringItems)BitConverter.ToInt32(keyData, );

                , sizeof(int));
                );

                if (valLength > inputStream.Length)
                    throw new SerialisationException("Error deserializing packet header. Length string item was too large to be present in the input stream."+
                        " This error is typically thrown because a non NetworkComms.Net peer attempted to communicate. If this is desirable please consider using an unmanaged connection.");

                , valData.Length);
                string val = new String(Encoding.UTF8.GetChars(valData));

                stringItems.Add(key, val);
            }
        }

        #endregion

        /// <summary>
        /// Deserializes from a memory stream to a <see cref="PacketHeader"/> object
        /// </summary>
        /// <param name="inputStream">The memory stream containing the serialized <see cref="PacketHeader"/></param>
        /// <param name="result">The deserialized <see cref="PacketHeader"/></param>
        public static void Deserialize(Stream inputStream, out PacketHeader result)
        {
            result = new PacketHeader();
            result.Deserialize(inputStream);
        }
    }

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

  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. JavaScript—之对象参数的引用传递

    变量 1.JavaScript hoisting >>请看例子,我们拿Chrome的console作为JS的运行环境. 上面直接执行console.log(a), 不带一点悬念地抛出了no ...

  2. C# socket编程实践——支持广播的简单socket服务器

    在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# socket编程基本知识,写一个支持广播的简单server/clie ...

  3. Java框架搭建-Maven、Mybatis、Spring MVC整合搭建

    1. 下载eclipse 到网站下载 http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/marsr 选择 ...

  4. javascript之-深入事件机制

    作者:yuyuyu链接:https://zhuanlan.zhihu.com/p/24620643来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 1.1 事件绑定的方式 ...

  5. python面向对象随笔

    传送门:http://www.runoob.com/python/python-object.html

  6. js笔记——js里var与变量提升

    var是否可以省略 一般情况下,是可以省略var的,但有两点值得注意: 1.var a=1 与 a=1 ,这两条语句一般情况下作用是一样的.但是前者不能用delete删除.不过,绝大多数情况下,这种差 ...

  7. Atitit jsr规范有多少个  407个。Jsr规范大全

    Atitit jsr规范有多少个  407个.Jsr规范大全 1.1. JCP维护职能是发展和更新.1 1.2. Java技术规范.参考实现(RI).技术兼容包(TCK)1 1.3. JCP维护的规范 ...

  8. fir.im Weekly - 这是一份强大的 SwiftGuide

    大新闻!Apple 10 亿美元融资滴滴!库克大叔对中国 iOS 开发者表达了高度认可,同时也传出 iOS 10 将内置滴滴 App 的消息.想像下,某个加班的深夜飙完代码,最性感的事情莫过于:「Si ...

  9. KnockoutJS 3.X API 第五章 高级应用(2) 控制后代绑定

    注意:这是一种高级技术,通常仅在创建可重用绑定的库时使用. 默认情况下,绑定仅影响它们应用到的元素. 但是如果你想影响所有的后代元素呢? 为此,只需从绑定的init函数中返回{controlsDesc ...

  10. 了解canvas

    目录 [1]HTML属性[2]CSS样式 [3]API 坐标 填充和描边 阴影 绘制矩形 绘制路径 绘制文本 绘制图像 使用图像 变换 合成 [4]DEMO 前面的话 canvas元素是HTML5最受 ...