艾伟_转载:Socket开发探秘--数据封包和拆包

在上篇《Socket开发探秘--基类及公共类的定义 》中介绍过,所有受到的数据包,经过系统的预处理后,都会得到一个PreData的数据实体,该实体包含了协议头、协议内容和所属用户的ID。PreData是定义了一个标准的协议数据格式,包含了协议关键字、协议内容、用户标识的内容。
前面说了,我们数据是通过实体类作为载体的,我们知道,收到的Socket数据经过粗略的解析后,就是PreData类型的数据,这个是通用的数据格式,我们需要进一步处理才能转化为所能认识的数据对象(实体类对象),同样,我们发送数据的时候,内容部分肯定是按照一定协议规则串联起来的数据,那么我们就需要把实体转化为发送的数据格式。综上所述,我们通过实体类,必须实现数据的发送和读取的转换。

代码

    /// 
    /// 测试数据的实体类信息
    ///  
    public class TestDataRequest
    {
        #region MyRegion

        /// 
        /// 请求序列
        ///  
        public string seq;
        /// 
        /// 用户帐号
        ///  
        public string userid;
        /// 
        /// 用户密码
        ///  
        public string psw;

        #endregion

        public TestDataRequest(string seq, string userid, string psw)
        {
            this.seq = seq;
            this.userid = userid;
            this.psw = psw;
        }
        public TestDataRequest()
        {
        }

        /// 
        /// 转换Socket接收到的信息为对象信息
        /// 
        /// Socket接收到的信息
        public TestDataRequest(string data)
        {
            string[] dataArray = null;
            dataArray = NetStringUtil.UnPack(data);
            if (dataArray != null && dataArray.Length > 0)
            {
                TestDataRequest newAnswerData = new TestDataRequest();
                int i = 0;
                this.seq = dataArray[i++];
                this.userid = dataArray[i++];
                this.psw = dataArray[i++];
            } 
        }

        /// 
        /// 转换对象为Socket发送格式的字符串
        /// 
        /// 
        public override string ToString()
        {
            string data = "";
            data = this.seq + "|" + this.userid + "|" + this.psw.ToString();
            data = NetStringUtil.PackSend(DataTypeKey.TestDataRequest, data);
            return data;
        }

 

以上把数据的处理放在了实体类中进行封包和拆包,是一种比较好的做法,但是由于数据的封包拆包是一个繁琐的过程,代码重复性比较多,而且也容易出错。

这里设计了一个基类,来改进这种方式的数据处理,我们把所有对数据的拆包和封包,利用反射机制,减少我们的代码量,提高代码的优雅性。

代码

    public class BaseEntity
    {
        protected string HeaderKey;

        public BaseEntity()
        {
        }

        /// 
        /// 转换Socket接收到的信息为对象信息
        /// 
        /// Socket接收到的信息
        public BaseEntity(string data)
        {
            string[] dataArray = null;
            dataArray = NetStringUtil.UnPack(data);
            if (dataArray != null && dataArray.Length > 0)
            {
                int i = 0;
                FieldInfo[] fieldArray = ReflectionUtil.GetFields(this);
                if (fieldArray == null || dataArray.Length != fieldArray.Length)
                {
                    throw new ArgumentException("收到的信息和字段信息不一致");
                }

                if (fieldArray != null)
                {
                    foreach (FieldInfo info in fieldArray)
                    {
                        string strValue = dataArray[i++];
                        ReflectionUtil.SetField(this, info.Name, strValue);
                    }
                }
            }
        }

        /// 
        /// 转换对象为Socket发送格式的字符串
        /// 
        /// 
        public override string ToString()
        {
            string data = "";
            FieldInfo[] fieldArray = ReflectionUtil.GetFields(this);
            StringBuilder sb = new StringBuilder();
            if (fieldArray != null)
            {
                foreach (FieldInfo info in fieldArray)
                {
                    sb.Append(ReflectionUtil.GetField(this, info.Name));
                    sb.Append("|");
                }
            }

            data = sb.ToString().Trim('|');
            if (string.IsNullOrEmpty(HeaderKey))
            {
                throw new ArgumentNullException("DataTypeKey", "实体类未指定协议类型");
            }
            data = NetStringUtil.PackSend(HeaderKey, data);
            return data;
        }
    }

 

以上的是实体类的基类,它封装了数据的拆包和封包过程,只需要在子类代码中指定协议头就可以了。子类的代码如下所示。

代码

    /// 
    /// 测试请求
    /// 
    public class TestDataRequest : BaseEntity
    {
        #region 字段信息

        /// 
        /// 请求序列
        /// 
        public string Seq;

        /// 
        /// 用户帐号
        /// 
        public string UserId;

        /// 
        /// 用户密码
        /// 
        public string Password;

        /// 
        /// 消息时间
        /// 
        public DateTime CreateDate = DateTime.Now;

        #endregion

        public TestDataRequest()
        {
            this.HeaderKey = DataTypeKey.TestDataRequest;
        }

        public TestDataRequest(string seq, string userid, string psw)
        {
            this.Seq = seq;
            this.UserId = userid;
            this.Password = psw;
            this.HeaderKey = DataTypeKey.TestDataRequest;
        }

        /// 
        /// 转换Socket接收到的信息为对象信息
        /// 
        /// Socket接收到的信息
        public TestDataRequest(string data) : base(data)
        {
            this.HeaderKey = DataTypeKey.TestDataRequest;
        }
    }

下面的代码是收到数据包,利用实体类构造函数,解析为实体类的操作,以及构造实体类,通过ToString()方式把实体类信息转化为可以发送的数据包的操作。

代码

        private void TestDataHandle(PreData data)
        {
            TestDataRequest request = new TestDataRequest(data.Content);
            Log.WriteInfo(string.Format("############{0}", request.ToString()));

            TestDataAnswerData answerData = new TestDataAnswerData(request.Seq, request.UserId, request.Password);
            ShopClientManager.This.AddSend(data.UserId, answerData.ToString(), true);
        }

 

我编写的测试例子中,实体类的继承图如下所示。

时间: 2024-10-27 20:16:28

艾伟_转载:Socket开发探秘--数据封包和拆包的相关文章

Socket开发探秘--数据封包和拆包

在上篇<Socket开发探秘--基类及公共类的定义 >中介绍过,所有受到的数据包,经过系统的预处理后,都会得到一个PreData的数据实体,该实体包含了协议头.协议内容和所属用户的ID.PreData是定义了一个标准的协议数据格式,包含了协议关键字.协议内容.用户标识的内容.前面说了,我们数据是通过实体类作为载体的,我们知道,收到的Socket数据经过粗略的解析后,就是PreData类型的数据,这个是通用的数据格式,我们需要进一步处理才能转化为所能认识的数据对象(实体类对象),同样,我们发送数

艾伟_转载:ASP.NET数据缓存之数据缓存浅谈

ASP.NET数据缓存的学习是如何呢?如何使用ASP.NET数据缓存呢?在讲ASP.NET数据缓存之前还要先说一下如果在页面中使用参数缓存.前面讲过一个缓存设置VaryByParam="none"为无参数,我们也可以对VaryByParam进行设置,设置的参数与随 GET 方法属性发送的查询字符串值对应,或与使用 POST 方法发送的参数对应.将该属性设置为多个参数时,对于每个指定参数组合,输出缓存都包含一个不同版本的请求文档.可能的值包括 none.星号 (*) 以及任何有效的查询字

Socket开发探秘--基于Json格式的数据协议收发

前面发表过两篇随笔:<Socket开发探秘--基类及公共类的定义>和<Socket开发探秘-- 数据封包和拆包>,介绍了Socket方面的开发.本文继续探讨使用Json格式来作为Socket收 发协议方面的技术问题. 前面说到,收到的Socket数据经过粗略的解析后,就是PreData类型的数据,这个是通用 的数据格式,我们需要进一步处理才能转化为所能认识的数据对象(实体类对象),同样, 我们发送数据的时候,内容部分肯定是按照一定协议规则串联起来的数据,那么我们就需要 把实体转化为

艾伟_转载:Socket开发探秘--基类及公共类的定义

Socket开发是属于通信底层的开发,.NET也提供了非常丰富的类来实现Socket的开发工作,本篇不是介绍这些基础类的操作,而是从一个大的架构方面阐述Socket的快速开发工作,本篇以TCP模式进行程序的开发介绍,以期达到抛砖引玉的目的. 要掌握或者了解Socket开发,必须了解下面所述的场景及知识. 1.TCP客户端,连接服务器端,进行数据通信 2.TCP服务器端,负责侦听客户端连接 3.连接客户端的管理,如登陆,注销等,使用独立线程处理 4.数据接收管理,负责数据的接受,并处理队列的分发,

艾伟_转载:C# WinForm开发系列 - TextBox

包含金额/日期输入框,带弹出数字面板的计算输入框,安全密码输入等控件(文章及相关代码搜集自网络,仅供参考学习,版权属于原作者! ).   1.CalculatorBox    CalculatorBox.rar 2.带行号+自定义颜色显示的TextBox 3.金额输入框   currency_textbox.zip   CurrencyBox.rar   NumberPicker_src.zip   NumericTextBox_src.zip   NumberedTextbox.rar 4.日

艾伟_转载:如何开发绚丽、高效率的界面(Windows嵌入式系统)

上篇文章中提到用户体验(UE),并且说到国内有专门去做UE的团队也很少.据我了解Microsoft.Nokia.Google等,还有国内的Baidu是有比较专业的UE团队.对于我们这样的普通团队.普通开发者来说,这样的经验实在太少了.而且普遍更认为UE是UI Designer的事情,与我们这样的Developer没有太多关系. 当然不是,UE远超过UI.很多因素造成了UE差,比如一份不正确的数据表明17%的用户认为手机运行速度慢,Windows Mobile手机开机漫长的等待就十分的让我受不了.

艾伟_转载:Windows Mobile开发,Native C++ PK .NET Compact Framework

缘由 经常听到一些刚刚接触Windows Embedded CE和Windows Mobile开发的人会提出一些疑问.进行Windows Mobile开发,到底使用什么语言呢?C++还是C#?Java行不行?下面就我自己的想法讲述一下Native C++ 和 .NET Compact Framework的异同和选择.   什么是Native Native翻译成原生,Native是使用C,C++或者汇编等语言代码编写的,编译成处理器相关的binary文件(执行文件,DLL等可执行文件), 关于可执

艾伟_转载:40条ASP.NET开发Tip

1.在compilation 下,请设置debug=false ,如下: default Language="c#" debug="false"> 2.请使用Server.Transfer代替Response.Redirect. 3.使用Validator控件,请要经常检查Page.IsValid. 4.请使用foreach循环,而不是为字符串迭代循环. 5.请使用客户端验证方式(不要每次都在服务端验证). 6.为了避免重复代码执行,请检查"Page

艾伟_转载:ASP.NET实现类似Excel的数据透视表

    代码:/Files/zhuqil/Pivot.zip     数据透视表提供的数据三维视图效果,在Microsoft Excel能创建数据透视表,但是,它并不会总是很方便使用Excel.您可能希望在Web应用程序中创建一个数据透视报表.创建一个简单的数据透视表可能是一件非常复杂的任务.所以,我打算不但为你提供一个非常有用的工具创建简单和高级的数据透视表,而且为你移除一些笼罩他们的神秘面纱.    目标是:我们想要有能力将datatable中的二维的数据转换成三维视图.    在大多数情况