• 8,协议序列化组件NewLife.Serialization


    在开发某些需要跟第三方平台交互的项目时,往往需要解析或者构造符合对方协议要求的数据格式,该操作在.Net中有个很漂亮的名字——序列化!

    在实际使用中,XML序列化用得比较多,二进制序列化也不错,只是可控性很低。当然,对于要序列化指定协议的格式而言,它们就几乎帮不上忙了。于是有了“协议序列化组件NewLife.Serialization”。

     

    协议序列化类ProtocolFormatter的主旨是实现二进制格式数据和.Net实体数据之间的灵活转换!

     

    使用上非常简单,下面通过实现一个简单的消息类来反序列化手机QQ2008Mobile)的聊天记录。

    新建一个控制台项目,引用NewLife.Serialization.dll。加入下面的代码:

    FileStream stream = new FileStream("10000.rec", FileMode.Open);
    ProtocolFormatter formatter = new ProtocolFormatter(typeof(Message));
    formatter.Head.Config.NoHead = true;
    while (stream.Position < stream.Length)
    {
        try
        {
            Message msg = new Message();
            formatter.Deserialize(stream, msg);
    
            Console.WriteLine("{0}({1}) {2} {3}", msg.Name, msg.Number, msg.Time, msg.MsgKind);
            Console.WriteLine(msg.Content);
    
            if (BitConverter.ToString(msg.Data) != "00-00-00-00-00")
                Console.WriteLine("未知数据:{0}", BitConverter.ToString(msg.Data));
    
            Console.WriteLine();
        }
        catch (EndOfStreamException) { break; }
    }
    stream.Close();
    

    第一步实例化一个ProtocolFormatter对象,这里指定了类型为Message

    第二步实例化一个Message对象,这点跟许多组件的反序列化不同,因为有时候外部已经准备好了一个对象,反序列化只需要填充就可以了;

    第三步就是序列化,这里传入第二步实例化的对象。如果这里传入对象,第一步实例化ProtocolFormatter的时候,就可以不用指定类型了;这里也可以不传入对象,Deserialize方法内部会实例化一个返回。

    下面我们看看Message类:

    [ProtocolSerialProperty]
    public class Message : IProtocolSerializable
    {
        #region 属性
            private Int16 _Length;
            /// <summary>消息长度</summary>
            public Int16 Length
            {
                get { return _Length; }
                set { _Length = value; }
            }
    
            private String _Content;
            /// <summary>内容</summary>
            public String Content
            {
                get { return _Content; }
                set { _Content = value; }
            }
    
            private Int32 _Number;
            /// <summary>号码</summary>
            public Int32 Number
            {
                get { return _Number; }
                set { _Number = value; }
            }
    
            private String _Name;
            /// <summary>名称</summary>
            public String Name
            {
                get { return _Name; }
                set { _Name = value; }
            }
    
            private DateTime _Time;
            /// <summary>时间</summary>
            public DateTime Time
            {
                get { return _Time; }
                set { _Time = value; }
            }
    
            private Int16 _Unknown;
            /// <summary>未知</summary>
            public Int16 Unknown
            {
                get { return _Unknown; }
                set { _Unknown = value; }
            }
    
            private MsgKinds _MsgKind;
            /// <summary>消息类型</summary>
            public MsgKinds MsgKind
            {
                get { return _MsgKind; }
                set { _MsgKind = value; }
            }
    
            private Byte[] _Data;
            /// <summary>未知数据</summary>
            public Byte[] Data
            {
                get { return _Data; }
                set { _Data = value; }
            }
            #endregion
    
        #region 方法
            const Char tag = (Char)20;
            static String FixContent(String content)
            {
                content = content.Replace(tag + "A", "[/惊讶]");
                content = content.Replace(tag + "N", "[/呲牙]");
                content = content.Replace(tag + "M", "[/调皮]");
                content = content.Replace(tag + "x", "[/惊恐]");
                content = content.Replace(tag + "J", "[/大哭]");
                content = content.Replace(tag + "s", "[/难过]");
                content = content.Replace(tag + "e", "[/爱心]");
                content = content.Replace(tag + "o", "[/强]");
                content = content.Replace(tag + "K", "[/尴尬]");
                content = content.Replace(tag + "C", "[/色]");
                content = content.Replace(tag + "\\", "[/饱]");
                content = content.Replace(tag + "E", "[/得意]");
                content = content.Replace(tag + "b", "[/玫瑰]");
                content = content.Replace(tag + "v", "[/抓狂]");
                content = content.Replace(tag.ToString() + (Char)139, "[/可爱]");
                content = content.Replace(tag.ToString() + (Char)153, "[/再见]");
                content = content.Replace(tag.ToString() + (Char)138, "[/偷笑]");
                content = content.Replace(tag.ToString() + (Char)121, "[/流汗]");
                content = content.Replace(tag.ToString() + (Char)162, "[/擦汗]");
                content = content.Replace(tag.ToString() + (Char)171, "[/委屈]");
                content = content.Replace(tag.ToString() + (Char)141, "[/傲慢]");
                content = content.Replace(tag.ToString() + (Char)197, "[/献吻]");
                content = content.Replace(tag.ToString() + (Char)146, "[/疑问]");
                content = content.Replace(tag.ToString() + (Char)166, "[/坏笑]");
                content = content.Replace(tag.ToString() + (Char)149, "[/折磨]");
                content = content.Replace(tag.ToString() + (Char)168, "[/右哼哼]");
                content = content.Replace(tag.ToString() + (Char)170, "[/鄙视]");
                content = content.Replace(tag.ToString() + (Char)172, "[/快哭了]");
                content = content.Replace(tag.ToString() + (Char)181, "[/示爱]");
                content = content.Replace(tag.ToString() + (Char)140, "[/白眼]");
                content = content.Replace(tag.ToString() + (Char)174, "[/爱情]");
                content = content.Replace(tag.ToString() + (Char)182, "[/瓢虫]");
                content = content.Replace(tag.ToString() + (Char)161, "[/冷汗]");
    
                //if (content.Contains(tag.ToString())) throw new Exception("未识别!");
    
                return content;
            }
            #endregion
    
        #region IProtocolSerializable 成员
    
            object IProtocolSerializable.OnCreateInstance(ReadContext context, Type type)
            {
                return null;
            }
    
            void IProtocolSerializable.OnDeserialized(ReadContext context)
            {
            }
    
            bool IProtocolSerializable.OnDeserializing(ReadContext context)
            {
                BinaryReader reader = context.Reader;
                if (context.Node.Name == "Content")
                {
                    context.Data = ReadString(context.Reader);
                    return false;
                }
                else if (context.Node.Name == "Name")
                {
                    context.Data = ReadString2(context.Reader);
                    return false;
                }
                else if (context.Node.Name == "Time")
                {
                    Int32[] ds = new Int32[7];
                    Int32 m = 0;
                    for (int i = 0; i < ds.Length; i++)
                    {
                        ds[i] = reader.ReadInt16();
                    }
    
                    DateTime dt = new DateTime(ds[0], ds[1], ds[3], ds[4], ds[5], ds[2], DateTimeKind.Utc);
                    context.Data = dt.ToLocalTime();
                    return false;
                }
                else if (context.Node.Name == "Data")
                {
                    context.Data = context.Reader.ReadBytes(5);
                    return false;
                }
    
                return true;
            }
    
            static String ReadString(BinaryReader reader)
            {
                Int32 msglen = reader.ReadInt16();
                if (reader.BaseStream.Position > 4) msglen = reader.ReadInt16();
                Byte[] buffer = reader.ReadBytes(msglen);
                String str = Encoding.Unicode.GetString(buffer);
                str = FixContent(str);
                return str;
            }
    
            static String ReadString2(BinaryReader reader)
            {
                Int32 msglen = reader.ReadInt16();
                Byte[] buffer = reader.ReadBytes(msglen * 2);
                String str = Encoding.Unicode.GetString(buffer);
                str = FixContent(str);
                return str;
            }
    
            void IProtocolSerializable.OnSerialized(WriteContext context)
            {
            }
    
            bool IProtocolSerializable.OnSerializing(WriteContext context)
            {
                return true;
            }
    
            #endregion
    }
    
    public enum MsgKinds : short
        {
            系统消息 = 0x110,
            带链接系统消息 = 0x116,
            新邮件 = 0x117,
            请求加好友 = 0x122,
            通过加好友请求 = 0x0123
        }
    

    Message类主要包含三大部分:

    第一是属性,这点从分析手机QQ2008聊天记录文件的格式可以得出。我是一边试一遍猜,猜出来的;

    第二是重点。这个类实现了IProtocolSerializable接口,通过OnDeserializing来改变反序列化的行为,某些属性需要特殊处理的,就在这里处理。

    第三部分是处理聊天记录里面的表情,这个可有可无。

    Message类上面有个ProtocolSerialProperty特性,指定反序列化的时候,分析属性,而不是默认的分析字段。这里指定分析属性,只是为了方便下面写代码判别名称。

    执行效果如下:

    wps_clip_image-9886

     

    协议序列化组件完全通过反射实现,层层深入,所以性能非常差!我们主要用来序列化BT种子以及各种用于网络传输的指令,因为指令对象简单,性能上还可以接受。

     

    大石头

    新生命开发团队

    2010-09-29 10758

    组件示例下载

  • 相关阅读:
    线程与并发系列一:Lock、Monitor、UserSpinLock
    什么是WebService
    异步和多线程有什么区别
    java.sql.SQLException: The server time zone value '' is unrecognized or represents
    java.sql.SQLException: Unable to load authentication plugin 'caching_sha2_password'.
    本地如何查看zookeeper注册了哪些服务
    maven的archetype
    Windows下安装ZooKeeper
    Dubbo架构和原理
    IntelliJ IDEA 2019.2.4破解
  • 原文地址:https://www.cnblogs.com/nnhy/p/1838727.html
Copyright © 2020-2023  润新知