开发者社区> 长征6号> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

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

 

组件示例下载

我不相信神话,我只相信汗水!我不相信命运,我只相信双手!

分类: X组件


本文转自大石头博客园博客,原文链接:http://www.cnblogs.com/nnhy/archive/2010/09/29/1838727.html,如需转载请自行联系原作者,如需转载请自行联系原作者

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

相关文章
MSMQ实现自定义序列化存储
MSMQ实现自定义序列化存储 http://www.ikende.com/blog/6d944821cadc4023a4940015b74e2804 在使用MSMQ的时候一般只会使用默认的XML序列化来对消息进行存储,但XML存储的缺点是序列化体积相对比较大和效率上有点低.
531 0
序列化和反序列化,异步调用web/wcf/函数
//xml序列化 public static string Seria(DataSet ds) { XmlSerializer serializer = new XmlSe...
555 0
wcf 基础教程 之已知类型KnownType 数据契约序列化DataContractSerializer
上一篇博客中我们介绍到了数据契约的序列化操作,虽然数据契约的序列化和xml的序列化操作基本保持一致,除了一些细小的差别外,但是数据契约的序列化更加简单,更加方便。今天我们继续数据契约的序列化,只不过今天要讨论的问题不是如何序列化,而是如何保证序列化成功。
551 0
wcf基础教程之 数据契约的序列化DataContractSerializer
上一篇博客我们说明了数据契约的前身Xml的序列化,这次还是言归正传,回到wcf的技术上来,分析一下DataContractSerializer 。 首先我们必须了解wcf默认是通过xml进行数据传输,但是并不意味着就一定要用这种,还有轻量级的json。
447 0
wcf 基础教程 契约 Contract 数据契约DataContract序列化前身 XmlSerializer xml序列化
本来今天打算描述一下数据契约的序列化,毕竟只是单纯的说数据契约的作用也没有太大意义,但是我发现如果单纯的叙述wcf的序列胡DataSerializer 很困难,因为它采用的事xml序列化,所以今天打乱了我的计划,来介绍一下.Net中的xml序列化,毕竟我们在使用序列化器的时候,很多时候生成的都是xml。
610 0
wcf 基础教程 契约 Contract 控制xml输出 数据契约DataContract序列化前身 XmlSerializer xml序列化
在上一篇博客介绍了xml序列化的原则,wcf 基础教程 契约 Contract 数据契约DataContract序列化前身 XmlSerializer xml序列化, 今天我们沿着上次描述的继续前进,这次的内容可能会很少,但是应该说如果我们想更进一步的控制xml,那么还是很有必要的。
615 0
8,协议序列化组件NewLife.Serialization
在开发某些需要跟第三方平台交互的项目时,往往需要解析或者构造符合对方协议要求的数据格式,该操作在.Net中有个很漂亮的名字——序列化! 在实际使用中,XML序列化用得比较多,二进制序列化也不错,只是可控性很低。
505 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载