介绍开源的.net通信框架NetworkComms框架 源码分析(四)Packet
原文网址: 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的更多相关文章
- DotNetty网络通信框架学习之源码分析
DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...
- 深入理解分布式调度框架TBSchedule及源码分析
简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...
- 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)
1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...
- 设计模式(二十一)——解释器模式(Spring 框架中SpelExpressionParser源码分析)
1 四则运算问题 通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输入表达式的形式,比如 a+b+c-d+e, 要求表达式的字母不能重复 2) 在分别输入 a ,b, c, ...
- $Django cbv源码分析 djangorestframework框架之APIView源码分析
1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...
- ④NuPlayer播放框架之Renderer源码分析
[时间:2016-11] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,渲染器,render] 0 导读 之前我们分析了NuPlayer的实现代码,本文将重点聚 ...
- ⑤NuPlayer播放框架之GenericSource源码分析
[时间:2017-01] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,GenericSource] 0 导读 GenericSource是NuPlayer:: ...
- ③NuPlayer播放框架之类NuPlayer源码分析
[时间:2016-10] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架] 0 引言 差不多一个月了,继续分析AOSP的播放框架的源码.这次我们需要深入分析的是N ...
- Laravel开发:Laravel框架门面Facade源码分析
前言 这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facades(读音:/fəˈsäd/ )为应用程序的服务容器中可用的类提供了一个「静态」接口.Lara ...
- Android 应用框架层 SQLite 源码分析
概述 Android 在应用框架层为开发者提供了 SQLite 相关操作接口,其归属于android.database.sqlite包底下,主要包含SQLiteProgram, SQLiteDat ...
随机推荐
- 翻译-DevOps究竟是什么?
原文地址:http://www.drdobbs.com/architecture-and-design/what-exactly-is-devops/240009147 作者:Neil Garnich ...
- Windows 10 下安装 npm 后全局 node_modules 和 npm-cache 文件夹的设置
npm 指 Node Package Manager,是 Node.js 中一个流行的包管理和分发工具.Node.js 在某个版本的 Windows 安装包开始已经加入了 npm,现在可以进入 htt ...
- Amazon Dynamo论文学习
Dynamo是一个key-value数据存储系统,去中心化.高可扩展.高可用,使用一致性哈希来分区和备份数据,使用数据版本化来实现一致性. 核心技术 CAP:一致性.可用性.扩展性 一致性哈希:切分数 ...
- jdk研究——java.lang
jdk研究 volatile 是什么意思? 如何看jdk源码? 如何调试源码!---------仔细解读关键类,关键代码,常用的api的解释! 自己有疑问的不懂地方-------- 不懂的太多怎么办. ...
- wep.py输出hello world
webpy是python的一个简单的web开发的框架.可以通过简单的几行代码启动一个web服务(虽然只是输出helloworld). 准备工作 准备工具如下: 下载python[python开发环境] ...
- Lua标准库- 模块(Modules)
Lua包库为lua提供简易的加载及创建模块的方法,由require.module方法及package表组成 1.module (name [, ···]) 功能:建立一个模块. module的处理流程 ...
- 了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发)
了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发) Guillermo Rauch 编 赵静 译 ISBN 978-7-121-21769-2 2 ...
- Sublime Text配置Python开发利器
Sublime Text配置Python开发利器 收好了 自动提示 jedi 代码格式化 Python PEP8 autoformat 如果还需要在shell中搞搞研究的话,ipython将是很好的选 ...
- Netty学习五:Buffers
1. Netty中的缓冲 在Netty中并没有使用Java自带的ByteBuffer,而是自己实现提供了一个缓存区来用于标识一个字节序列,并帮助用户操作原始字节或者自定义的POJO. Java NIO ...
- 【WP 8.1开发】自定义(RAW)通知的使用
继续前面的话题,还是推送通知.上一篇文章中遗留了RAW通知的推送没有给各位演示,特特地留到现在,不为别的,只为这个RAW通知有点意思,玩起来会比较有意思.官方文档将RAW通知译为“原始通知”,这里还是 ...