艾伟_转载:Socket开发探秘--数据封包和拆包-阿里云开发者社区

开发者社区> 狼人2007> 正文

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

简介: 在上篇《Socket开发探秘--基类及公共类的定义 》中介绍过,所有受到的数据包,经过系统的预处理后,都会得到一个PreData的数据实体,该实体包含了协议头、协议内容和所属用户的ID。PreData是定义了一个标准的协议数据格式,包含了协议关键字、协议内容、用户标识的内容。
+关注继续查看

在上篇《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);
        }

 

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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
数据解析之 XPath & lxml 库
数据解析之 XPath & lxml 库
11 0
自然语言处理 NLP(4)
自然语言处理 NLP(4)
13 0
Java 设计模式
Java 设计模式
9 0
如何利用 Beautiful Soup 爬取网页数据
如何利用 Beautiful Soup 爬取网页数据
7 0
Kafka无消息丢失配置方案
kafka以其高性能、高吞吐、可扩展等出色能力,被广泛应用在各行各业,是事件流处理平台和消息队列中的佼佼者,但是经常可以看到有人在吐槽kafka消息丢失,但是真的是kafka的锅吗,本文我们就来认真分析一下到底哪些场景可能导致消息丢失以及使用怎么样的方案可以防止消息丢失。
12 0
从零实现一个日志框架(带源码)
Java里的各种日志框架,相信大家都不陌生。Log4j/Log4j2/Logback/jboss logging等等,其实这些日志框架核心结构没什么区别,只是细节实现上和其性能上有所不同。本文带你从零开始,一步一步的设计一个日志框架
3 0
基于flowcharting实现定制化业务链路动态监控
flowcharting是grafana社区提供的一款插件,其借助开源绘图工具drawio可以实现定制化的的业务链路动态监控,将各项监控指标以更加面向业务的图表形式进行展示,可以实现网络拓扑图、流程图、架构图等等各种图形,将比较分散的指标统一成可视化的监控图形。
9 0
小程序的开发之使用SVG
昨天突然提出要在小程序中使用SVG,因为我们的小程序项目是有主题色的。不同的主题色时有些图片一直是固定的,显的有些格格不入,所以打算使用SVG来实现根据主题色的颜色进行变化。
17 0
Spring 中经典的 9 种设计模式,打死也要记住啊!
实现方式: BeanFactory。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。
6 0
Python知识点总结篇(4)
Python知识点总结篇(4)
11 0
+关注
狼人2007
个人对技术的追求:代码少而精捍;思路清晰美观;可扩展好维护;技术驱动商业; 人生格言:只要你有信念,有追求,并且坚持,那你一定比随波逐流,行得远行得正...
3528
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载