zoukankan      html  css  js  c++  java
  • (六)分布式通信----MessagePack序列化

    ==>>点击查看本系列文章目录

    1. .Net Core的序列化方式

    1.1 json.Net

    常用的工具包,如Newtonsoft.Json, 它是基于json格式的序列化和反序列化的组件

    json.net 有以下优点:

           侵入性:可以不添加attribute,就能进行序列化操作

           灵活性:可以灵活性配置,比如允许被序列化的成员自定义名字,屏蔽的非序列化属性成员

           可读性: 数据格式比较简单, 易于读写

           依赖性:可以序列化成JObject,无需依赖对象进行序列化和泛型化。

    1.2 protobuf

    它是基于二进制格式的序列化和反序列化的组件

    protobuf 有以下优点:

         性能高 : 序列化后体积相比Json和XML很小,适合RPC二进制传输
       跨语言:支持跨平台多语言
            兼容性:消息格式升级和兼容性还不错
            速度快 :序列化反序列化速度很快,快于Json的处理速度

    1.3 messagepack

    它是基于二进制格式的序列化和反序列化的组件

    messagepack有以下优点:

          性能高:序列化后体积相比Json和XML很小,适合RPC二进制传输
       跨语言:支持跨平台多语言
            兼容性:消息格式升级和兼容性还不错
            速度快 :序列化反序列化速度很快,快于Json的处理速度

    messagepack不管是小数据量还是大数据量都保持比较稳定的性能,本文中使用messagepack序列化方式。

    2. 项目编码及设计模式

     如下是文件结构:

    2.1 工厂模式

    抽象接口  工厂负责创建编码器和解码器

    1.工厂

        /// <summary>
        /// 一个抽象的传输消息编解码器工厂。
        /// </summary>
        public interface ITransportMessageCodecFactory
        {
            /// <summary>
            /// 获取编码器。
            /// </summary>
            /// <returns>编码器实例。</returns>
            ITransportMessageEncoder GetEncoder();
    
            /// <summary>
            /// 获取解码器。
            /// </summary>
            /// <returns>解码器实例。</returns>
            ITransportMessageDecoder GetDecoder();
        }

     2.编码器

        /// <summary>
        /// 编码器
        /// </summary>
        public interface ITransportMessageEncoder
        {
            byte[] Encode(TransportMessage message);
        }

     3.解码器

        /// <summary>
        /// 解码器
        /// </summary>
        public interface ITransportMessageDecoder
        {
            TransportMessage Decode(byte[] data);
        }

    实现类  工厂、编码器、解码器为MessagePack的实现

    1.工厂

       public sealed class MessagePackTransportMessageCodecFactory : ITransportMessageCodecFactory
        {
            #region Field
            private readonly ITransportMessageEncoder _transportMessageEncoder = new MessagePackTransportMessageEncoder();
            private readonly ITransportMessageDecoder _transportMessageDecoder = new MessagePackTransportMessageDecoder();
            #endregion Field
    
            #region Implementation of ITransportMessageCodecFactory
    
            /// <inheritdoc />
            /// <summary>
            /// 获取编码器 
            /// </summary>
            /// <returns></returns>
            public ITransportMessageEncoder GetEncoder()
            {
                return _transportMessageEncoder;
            }
    
            /// <inheritdoc />
            /// <summary>
            /// 获取解码器 
            /// </summary>
            /// <returns></returns>
            public ITransportMessageDecoder GetDecoder()
            {
                return _transportMessageDecoder;
            }
            #endregion Implementation of ITransportMessageCodecFactory
        }

     2.编码器

        public sealed class MessagePackTransportMessageEncoder : ITransportMessageEncoder
        {
            #region Implementation of ITransportMessageEncoder
    
            public byte[] Encode(TransportMessage transportMessage)
            {
                MessagePackTransportMessage messagePackTransportMessage = new MessagePackTransportMessage(transportMessage);
                return MessagePackSerializer.Serialize(messagePackTransportMessage);
            }
            
            #endregion Implementation of ITransportMessageEncoder
        }

     3.解码器

        public sealed class MessagePackTransportMessageDecoder : ITransportMessageDecoder
        {
            #region Implementation of ITransportMessageDecoder
    
            public TransportMessage Decode(byte[] data)
            {
                MessagePackTransportMessage messagePackTransportMessage = MessagePackSerializer.Deserialize<MessagePackTransportMessage>(data);
                return messagePackTransportMessage.GetTransportMessage();
            }
    
            #endregion Implementation of ITransportMessageDecoder
        }

    2.2 装饰器模式

    高层的消息模型:

        public class TransportMessage
        {
            /// <summary>
            /// 消息Id。
            /// </summary>
            public string Id { get; set; }
    
            /// <summary>
            /// 消息内容。
            /// </summary>
            public object Content { get; set; }
    
            /// <summary>
            /// 内容类型。
            /// </summary>
            public string ContentType { get; set; }
        }

     由于MessagePack序列化方式具有侵入性,需要添加 MessagePackObjectAttribute 和 KeyAttribute 特性,因此需要对 TransportMessage 做装饰:

    using MessagePack;
    
        [MessagePackObject]
        public class MessagePackTransportMessage
        {
            private TransportMessage _transportMessage;
            public MessagePackTransportMessage(): this(new TransportMessage())
            {
            }
    
            public MessagePackTransportMessage(TransportMessage transportMessage)
            {
                this._transportMessage = transportMessage;
            }
    
            public TransportMessage GetTransportMessage()
            {
                return _transportMessage;
            }
            /// <summary>
            /// 消息Id。
            /// </summary>
            [Key(0)]
            public string Id
            {
                get { return _transportMessage.Id; }
                set { _transportMessage.Id = value; }
            }
    
            /// <summary>
            /// 消息内容。
            /// </summary>
            [Key(1)]
            public object Content
            {
                get { return _transportMessage.Content; }
                set { _transportMessage.Content = value; }
            }
    
            /// <summary>
            /// 内容类型。
            /// </summary>
            [Key(2)]
            public string ContentType
            {
                get { return _transportMessage.ContentType; }
                set { _transportMessage.ContentType = value; }
            }
        }

    2.3 依赖注入

     Autofac 是一个依赖注入工具包,比.net Core 原始的依赖注入拥有更完善的功能,中文官方文档:https://autofaccn.readthedocs.io/zh/latest/index.html

    using Autofac;
    
        public static class ContainerBuilderExtensions
        {
            /// <summary>
            /// 使用messagepack编码解码方式
            /// </summary>
            /// <param name="builder"></param>
            /// <returns></returns>
            public static ContainerBuilder UseMessagePackCodec(this ContainerBuilder builder)
            {
                builder.RegisterType(typeof(MessagePackTransportMessageCodecFactory)).As(typeof(ITransportMessageCodecFactory)).SingleInstance();
                return builder;
            }
        }

     2.4 单元测试

    端到端的测试,同时测试编码和解码

    using MessagePack;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
        [TestClass]
        public class MessagePackTest
        {
            [TestMethod]
            public void TestCodec()
            {
                Person person = new Person
                {
                    Name = "张宏伟",
                    Age = 18
                };
                TransportMessage transportMessage = new TransportMessage
                {
                    Id = "1",
                    ContentType = "Person",
                    Content = person
                };
                MessagePackTransportMessageCodecFactory factory = new MessagePackTransportMessageCodecFactory();
                ITransportMessageEncoder encoder = factory.GetEncoder();
                ITransportMessageDecoder decoder = factory.GetDecoder();
                byte[] vs = encoder.Encode(transportMessage);
                TransportMessage message =decoder.Decode(vs);
                Assert.AreEqual(message.Id, "1");
                Assert.AreEqual(message.ContentType, "Person");
                Assert.AreEqual(((object[])message.Content)[0].ToString(), "张宏伟" );
                Assert.AreEqual(((object[])message.Content)[1].ToString(), "18");
            }
    
            [MessagePackObject]
            public class Person
            {
                [Key(0)]
                public string Name { get; set; }
                [Key(1)]
                public int Age { get; set; }
            }
        }
  • 相关阅读:
    【基本知识】verilog中 `define 的使用
    netsuite弹出窗体的数据回传例子
    js使用confirm对用户的行为进行判断 和prompt
    银行支付 接口
    关于IT公司的预见性
    js fix小数点 和int的区别
    ajax和Java session监听
    NetSuite全功能介绍 totemsuite netsuite开发模块
    财务软件间的财务接口(转载)
    去除eclipise f2功能 去除浮动窗口
  • 原文地址:https://www.cnblogs.com/hongwei918/p/11300191.html
Copyright © 2011-2022 走看看