博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Silverlight Tcp通讯中使用Protobuf.net
阅读量:6224 次
发布时间:2019-06-21

本文共 6153 字,大约阅读时间需要 20 分钟。

    Protobuf.net是Protobuf协议在.net平台下的实现,它支持源生的.net程序,Silverlight和window phon7的二进制序列化功能.在这里主要讲述在Silverlight Tcp通讯中使用Protobuf.net.在实现通讯前行制定一个通讯协议,主要是描述Protobuf.net序列化后的传输格式和获取时如何反序列化.

协议描述主要分为3部分首先是描述消息的总长度,然后跟着就是消息的类型名称,组件通过应该名称来创建对应的消息对象,最后面跟着的就是相关对象的Protobuf序列化数据。

    协议确定后就可以进行代码实现,由于之前已经写了一个Silverlight Tcp组件Beetle.SL(项目地址:);所以直接在它基础上扩展就OK了。需要做的工作有两项:实现一个消息适配器和一个协议分析器。在实现之前当然是要引用ProtoBuf.net这个组件可以到获取。

消息适配器实现如下

1     public class MessageAdapter:Beetle.IMessage 2     { 3         public object Message 4         { 5             get; 6             set; 7         } 8         static Dictionary
mTypes = new Dictionary
(256); 9 static Dictionary
mNames = new Dictionary
(256);10 public static void LoadMessage(System.Reflection.Assembly assembly)11 {12 foreach (Type t in assembly.GetTypes())13 {14 ProtoBuf.ProtoContractAttribute[] pc = (ProtoBuf.ProtoContractAttribute[])t.GetCustomAttributes(typeof(ProtoBuf.ProtoContractAttribute), false);15 if (pc.Length > 0)16 {17 string name = t.Name;18 NameAttribute[] na = (NameAttribute[])t.GetCustomAttributes(typeof(NameAttribute), false);19 if (pc.Length > 0)20 if(na.Length>0)21 {22 name = na[0].Name;23 }24 mTypes.Add(name, t);25 mNames.Add(t, name);26 }27 }28 }29 public static void Send(Beetle.TcpChannel channel, object message)30 {31 MessageAdapter ma = new MessageAdapter();32 ma.Message = message;33 channel.Send(ma);34 }35 public void Load(Beetle.BufferReader reader)36 {37 string type = reader.ReadString();38 byte[] data = reader.ReadByteArray();39 using (System.IO.Stream stream = new System.IO.MemoryStream(data,0,data.Length))40 {41 Message = ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(stream, null, mTypes[type]);42 }43 44 }45 public void Save(Beetle.BufferWriter writer)46 {47 writer.Write(mNames[Message.GetType()]);48 byte[] data;49 using (System.IO.Stream stream = new System.IO.MemoryStream())50 {51 ProtoBuf.Meta.RuntimeTypeModel.Default.Serialize(stream, Message);52 53 data = new byte[stream.Length];54 stream.Position = 0;55 stream.Read(data, 0, data.Length);56 57 }58 59 writer.Write(data);60 61 62 }63 }

整个过程实现是比较简单的就是根据协议制定的内容来把序列化信息写入BufferWriter,在获取消息的时候也是同样的方式从BufferReader中获取。

分包器的实现

Beetle.SL已经提供基于头描述大小的分包器,所以实现就更加简单了

public class ProtoBufHeadSizePackage:Beetle.HeadSizeOfPackage    {        public ProtoBufHeadSizePackage()        {        }        protected override void WriteMessageType(IMessage msg, BufferWriter writer)        {                    }        protected override IMessage ReadMessageByType(BufferReader reader, out object typeTag)        {            typeTag = "MessageAdapter";            return new MessageAdapter();        }    }

为了简单定义连接也继承TcpChannel实现一个ProtobufChannel

public class ProtoBufChannel:TcpChannel    {        public ProtoBufChannel()            : base(new ProtoBufHeadSizePackage())        {        }    }

    以下工作完成后,就可以在Silverlight Tcp通讯使用ProtoBuf.net来处理对象了,以下是制定一些简单的信息。

[ProtoContract]    public class Search    {        [ProtoMember(1)]        public string CompanyName { get; set; }        [ProtoMember(2)]        public string City { get; set; }        [ProtoMember(3)]        public string Region { get; set; }    }    [ProtoContract]    public class SearchResult    {        [ProtoMember(1)]        public List
Customers { get; set; } } [ProtoContract] public class GetCustomerOrders { [ProtoMember(1)] public string CustomerID { get; set; } } [ProtoContract] public class CustomerOrders { [ProtoMember(1)] public IList
Orders { get; set; } }

    消息制定后就可以定义连接了

private ProtoBufChannel mChannel = new ProtoBufChannel();        private void UserControl_Loaded(object sender, RoutedEventArgs e)        {            MessageAdapter.LoadMessage(this.GetType().Assembly);            mChannel.Connected += OnConnected;            mChannel.Disposed += OnDisposed;            mChannel.Receive += OnReceive;            mChannel.Error += OnError;        }

    连接创建后绑定相关事件,主要事件有4个分别是连接成功,连接释放,连接处理错误和数据接收事件。当这些事件定义后只需要调用一个简单Connect方法即可连接到指定IP端口的TCP服务.

private void cmdConnect_Click(object sender, RoutedEventArgs e)        {            mChannel.Connect(txtIP.Text,4520);        }

    连接后可以直接使用Channel发送Protobuf.net可序列化的对象.

private void cmdSearch_Click(object sender, RoutedEventArgs e)        {            Packages.Search search = new Packages.Search();            search.CompanyName = txtCompany.Text;            MessageAdapter.Send(mChannel, search);        }

    可以在接收数据事件根据不同的消息类型来进行一个输出处理.

private void OnReceive(object sender, EventChannelReceiveArgs e)        {            MessageAdapter adapter = (MessageAdapter)e.Message;            if (adapter.Message is Packages.SearchResult)            {                Packages.SearchResult searchresult = (Packages.SearchResult)adapter.Message;                this.Dispatcher.BeginInvoke(() => {                    dgCustomers.ItemsSource = searchresult.Customers;                });            }            else if (adapter.Message is Packages.CustomerOrders)            {                Packages.CustomerOrders orders = (Packages.CustomerOrders)adapter.Message;                this.Dispatcher.BeginInvoke(() =>                {                    dbOrders.ItemsSource = orders.Orders;                });            }        }

    以上是一个简单的数据查询事例

具体代码可以到 获取

转载地址:http://cpyna.baihongyu.com/

你可能感兴趣的文章
一个页面标题和过滤输出的解决方案(上)
查看>>
python pip install 出现 OSError: [Errno 1] Operation not permitted
查看>>
oracle12C 重做日志
查看>>
Linux ubuntu lamp安装配置环境phpmyadmin
查看>>
data guard 的部署
查看>>
枚举、模拟、递推
查看>>
sublime text 3安装
查看>>
awk-sed
查看>>
EXTJS4-----前言
查看>>
iOS11里判断Safari浏览器是无痕模式还是正常模式?
查看>>
zookeeper与kafka安装部署及java环境搭建(发布订阅模式)
查看>>
error C2244 "无法将函数定义与现有的声明匹配"的解决方法
查看>>
记一个 dubbo中hessian2反序列化 Map 的一个问题
查看>>
HDU_1505_矩阵中的最大矩形_dp
查看>>
HDU_1398_母函数
查看>>
leetcode_1039. Minimum Score Triangulation of Polygon_动态规划
查看>>
mysql 将时间戳与日期时间的转换
查看>>
个人作业-Week2 案例分析
查看>>
SVN提交错误及使用技巧
查看>>
服务器程序和应用程序
查看>>