博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Beetle在TCP通讯中使用二进制序列化对象传输
阅读量:6297 次
发布时间:2019-06-22

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

组件发送的对象都必须实现IMessage接口,通过实现接口来描述一个对象的序列化过程;自定义读写流的好处就是可以得到更好的性能,但缺点也相对明显的就是工作量比较多.在很多应用场合下所追求的并不是性能第一,而是希望省下这些烦锁的工作,为了应付这种需要组件可以实现一个简单的消息适配器来完成这样的功能.下面通过扩展的方式来实现组件对.net二进制序列化对象转输的支持.

定义协议格式

在TCP下进行数据交互通讯首先是要制定一个通讯的应用协议,由于组件提供基于结束符和头大小描述的基础分析器,可以从这基础分析协中派生下来.似下通过一个图来描述协议的具体细节

协议描述比较简单消息头是4个字节用于存储消息的总长度,而序列化存储的数据则是总长度减去头4位.

实现具体的分析器和消息适配器

协议制定后就可以进行分析器的实现,由于采用头4字节描述大小,所以分析器从HeadSizeOfPackage基础类派生下载重写相关方法即可;完整实现代码如下:

public class BinaryFormatterPackage:HeadSizeOfPackage    {        public BinaryFormatterPackage()        {        }                public BinaryFormatterPackage(TcpChannel channel)            : base(channel)        {        }             public override object ReadCast(object message)        {            return ((MessageAdapter)message).Message;        }        public override object WriteCast(object message)        {            MessageAdapter adapter = new MessageAdapter();            adapter.Message = message;            return adapter;        }        public override IMessage MessageRead(BufferReader reader)        {            IMessage msg = null;            object typeTag;            msg = ReadMessageByType(reader, out typeTag);            if (msg == null)                throw NetTcpException.TypeNotFound(typeTag.ToString());            try            {                msg.Load(reader);            }            catch (Exception e)            {                NetTcpException err = NetTcpException.ObjectLoadError(typeTag.ToString(), e);                throw err;            }            return msg;        }        protected override void WriteMessageType(IMessage msg, BufferWriter writer)        {                    }        protected override IMessage ReadMessageByType(BufferReader reader, out object typeTag)        {            typeTag = "Adapter";            return new MessageAdapter();        }        class MessageAdapter:IMessage        {            public object Message            {                get;                set;            }            public void Load(BufferReader reader)            {                ByteArraySegment bas = ByteArraySegment;                try                {                    int count = reader.ReadInt32();                    reader.Read(count - 4, bas);                                     using (System.IO.MemoryStream stream = new System.IO.MemoryStream(bas.Array, 0, bas.Count))                    {                        Formatter formater = new Formatter();                        Message = formater.Deserialize(stream);                    }                }                catch(Exception e_)                {                    throw e_;                }                            }            public void Save(BufferWriter writer)            {                ByteArraySegment bas = ByteArraySegment;                try                {                                        using (System.IO.MemoryStream stream = new System.IO.MemoryStream(bas.Array))                    {                        Formatter formater = new Formatter();                        formater.Serialize(stream, Message);                        bas.SetInfo(0, (int)stream.Position);                    }                    writer.Write(bas.Array, 0, bas.Count);                }                catch (Exception e_)                {                    throw e_;                }                           }            [ThreadStatic]            private static ByteArraySegment mByteArraySegment = null;            public ByteArraySegment ByteArraySegment            {                get                {                    if (mByteArraySegment == null)                        mByteArraySegment = new ByteArraySegment(TcpUtils.DataPacketMaxLength);                    return mByteArraySegment;                }            }        }    }

分析器主要重写了ReadCast,WriteCast和MessageRead方法,而两个Cast方法主要是把消息进行一个适配器包装到一个IMessage对象中提供给组件处理.通过适配器MessageAdapter来实现终于对象的序列化和反序列化操作,并整合的流中. 有了以上实现那就可以对.NET二制序列化的对象进行处理了,以下制订一个简单的注册对象.

[Serializable]    public class Register    {        public string UserName { get; set; }        public string EMail { get; set; }        public DateTime ResponseTime { get; set; }    }

实现相应的TCP服务

协议分析器扩展完成后就通过它来实现一个基于对象序列化的TCP交互服务.

class Program:ServerBase
{ static void Main(string[] args) { TcpUtils.Setup("beetle"); Program server = new Program(); server.Open(9034); Console.WriteLine("service start @9034"); System.Threading.Thread.Sleep(-1); } protected override void OnConnected(object sender, ChannelEventArgs e) { base.OnConnected(sender, e); Console.WriteLine("{0} connected!", e.Channel.EndPoint); } protected override void OnDisposed(object sender, ChannelDisposedEventArgs e) { base.OnDisposed(sender, e); Console.WriteLine("{0} disposed!", e.Channel.EndPoint); } protected override void OnError(object sender, ChannelErrorEventArgs e) { base.OnError(sender, e); Console.WriteLine("{0} error {1}!", e.Channel.EndPoint,e.Exception.Message); } protected override void OnMessageReceive(PacketRecieveMessagerArgs e) { base.OnMessageReceive(e); Register register = (Register)e.Message; register.ResponseTime = DateTime.Now; e.Channel.Send(register); } }

TCP服务的实现和原来的实现方式一致,只是继承的ServerBase的泛型参是基于对象序列化的协议分析器类型.

连接到服务进行对象通讯

同样接入服务端的代码只是改变一下泛型参类型即可

private void cmdConnect_Click(object sender, EventArgs e)    {        try        {            channel = Beetle.TcpServer.CreateClient
(txtIPAddress.Text, 9034, OnReceive); channel.ChannelDisposed += OnDisposed; channel.ChannelError += OnError; channel.BeginReceive(); cmdRegister.Enabled = true; cmdConnect.Enabled = false; } catch (Exception e_) { MessageBox.Show(e_.Message); } } private void OnReceive(Beetle.PacketRecieveMessagerArgs e) { Register reg = (Register)e.Message; Invoke(new Action
(r => { txtREMail.Text = r.EMail; txtRName.Text = r.UserName; txtResponseTime.Text = r.ResponseTime.ToString(); }), reg); } private void OnDisposed(object sender, Beetle.ChannelEventArgs e) { Invoke(new Action
(s => { txtStatus.Text = "disconnect!"; cmdRegister.Enabled = false; cmdConnect.Enabled = true; }), e); } private void OnError(object sender, Beetle.ChannelErrorEventArgs e) { Invoke(new Action
(r => { txtStatus.Text = r.Exception.Message; }), e); }

把对象发送给服务端

Register register = new Register();    register.EMail = txtEMail.Text;    register.UserName = txtName.Text;    channel.Send(register);

运行效果

下载代码:

总结

组件提供灵活的协议扩展功能,只需做简单的扩展工作就能实现不同序列化方式的对象信息传输.由于.net二进制序列化是自有的序列化方式,如果和其他平台交互信息并不是一个好的选择.在后面章节会介绍扩展Protobuf-net进行对象传输,它相对.net二进制序列化有着更多的优势.

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

你可能感兴趣的文章
小程序 · 跳转带参数写法,兼容url的出错
查看>>
flutter error
查看>>
Flask框架从入门到精通之模型数据库配置(十一)
查看>>
10年重新出发
查看>>
2019年-年终总结
查看>>
聊聊elasticsearch的RoutingService
查看>>
让人抓头的Java并发(一) 轻松认识多线程
查看>>
从源码剖析useState的执行过程
查看>>
地包天如何矫正?
查看>>
中间件
查看>>
Android SharedPreferences
查看>>
css面试题
查看>>
Vue组建通信
查看>>
用CSS画一个带阴影的三角形
查看>>
前端Vue:函数式组件
查看>>
程鑫峰:1.26特朗.普力挺美元力挽狂澜,伦敦金行情分析
查看>>
safari下video标签无法播放视频的问题
查看>>
01 iOS中UISearchBar 如何更改背景颜色,如何去掉两条黑线
查看>>
对象的继承及对象相关内容探究
查看>>
Spring: IOC容器的实现
查看>>