在处理TCP数据的时候我们需要考虑一个粘包的问题,所谓的粘包就是本次接收的数据不一定完整对应对方发送的数据.对方发送的一次数据有可能需要接收多次才能完成,实际要处理的情况要复习一点;为了解决点包问题所以必须要制订数据分析协议来处理,常用的解决方法有两种:一种是基于结束符的方式,而另一种则是在消息头通过一个4字节存储消息大小.

分包注意细节

虽然制定处理粘包的方法,但这两种方法在处理上还是要注意几种情况,以下通过一个图来表达几种情况的处理.

其实最主要关心的是就是分隔符或头描述的内容分别存放在两次receive的数据中.

实现一个简单的协议分析器

组件提供以上两种分包处理方式,基础类分别是HeadSizeOfPackage和EofDataOfPackage;通过继续以上两个类就可以简单地实现对象协议的发送和接收;如果以上两者不适合的情况可以从Package派生一个新的协议分析类来满足实际情况的需要. 接下来通过继承HeadSizeOfPackage实现一个简单的对象协议分析器,相关Package实现如下:

    public class HeadSizePackage:Beetle.HeadSizeOfPackage{public HeadSizePackage(Beetle.TcpChannel channel) : base(channel) { }private static Dictionary<string, Smark.Core.InstanceHandler> mTypes = new Dictionary<string, Smark.Core.InstanceHandler>(256);public static void LoadAssembly(System.Reflection.Assembly assembly){foreach (Type type in assembly.GetTypes()){if (type.GetInterface("Beetle.IMessage") != null && type.IsClass){mTypes[type.Name] = new Smark.Core.InstanceHandler(type);}}}protected override Beetle.IMessage ReadMessageByType(Beetle.BufferReader reader, out object typeTag){typeTag = reader.ReadShortString();Smark.Core.InstanceHandler handler;if (mTypes.TryGetValue((string)typeTag, out handler)){return (Beetle.IMessage)handler.Instance();}return null;}protected override void WriteMessageType(Beetle.IMessage msg, Beetle.BufferWriter writer){ writer.WriteShortString(msg.GetType().Name);}}

继承HeadSizeOfPackage后主要重写两个方法,分别是ReadMessageByType从BufferReader中读取对消息名称并返回具体的消息对象,WriteMessageType则是写入消息名称.两个方法的主要作用是写入消息类型标记和根据标记返回消息对象.制定完成协议分析后要做的事情就是制定对象协议,以下是一个简单注册协议实现:

    class Register : Beetle.IMessage{public string Name;public string EMail;public DateTime ResponseTime;public void Load(Beetle.BufferReader reader){Name = reader.ReadString();EMail = reader.ReadString();ResponseTime = reader.ReadDate();}public void Save(Beetle.BufferWriter writer){writer.Write(Name);writer.Write(EMail);writer.Write(ResponseTime);}}

构建对象协义的TCP服务端

在Beetle中构建基于对象协议的TCP服务端也是一件非常简单的事情,只需要Beetle.ServerBase<T>即可,而泛型参则是具体的协议分析器.

    class Program:Beetle.ServerBase<Beetle.Packages.HeadSizePackage>{protected override void OnConnected(object sender, Beetle.ChannelEventArgs e){base.OnConnected(sender, e);Console.WriteLine("{0} connected", e.Channel.EndPoint);}protected override void OnDisposed(object sender, Beetle.ChannelDisposedEventArgs e){base.OnDisposed(sender, e);Console.WriteLine("{0} disposed", e.Channel.EndPoint);}protected override void OnError(object sender, Beetle.ChannelErrorEventArgs e){base.OnError(sender, e);Console.WriteLine("{0} error {1}", e.Channel.EndPoint,e.Exception.Message);}protected override void OnMessageReceive(Beetle.PacketRecieveMessagerArgs e){Register reg = (Register)e.Message;reg.ResponseTime = DateTime.Now;Console.WriteLine("Name:{0} EMail:{1}", reg.Name, reg.EMail);e.Channel.Send(reg);}

和构建普通TCP服务一样,重写相关处理过程方法即可,不过其中一个方法有所不同就是OnMessageReceive,该对象主要包括接收的消息和对应的Socket通道TcpChannel.在之前只定义了一个Register对象消息,在这里就获取相关消息并把ResponseTime设置成当前时间后发还给对应的客户端.

构建客户端进行消息交互

客户端的创建则使用TcpServer.CreateClient<T>方法来构建,泛型参是对应协议分析器,具体代码如下:

    channel = Beetle.TcpServer.CreateClient<Beetle.Packages.HeadSizePackage>(txtIPAddress.Text, 9450,OnReceive);channel.ChannelDisposed += OnDisposed;channel.ChannelError += OnError;channel.BeginReceive();
        private void OnReceive(Beetle.PacketRecieveMessagerArgs e){Register reg = (Register)e.Message;Invoke(new Action<Register>(r => {txtREMail.Text = r.EMail;txtRName.Text = r.Name;txtResponseTime.Text = r.ResponseTime.ToString();}), reg);}private void OnDisposed(object sender, Beetle.ChannelEventArgs e){Invoke(new Action<Beetle.ChannelEventArgs>(s => {txtStatus.Text = "disconnect!";}), e);}private void OnError(object sender, Beetle.ChannelErrorEventArgs e){Invoke(new Action<Beetle.ChannelErrorEventArgs>(r => {txtStatus.Text = r.Exception.Message;}), e);}

构建连接后绑事相关事件,并进入数据接收模式即可.创建连接完成后就可以进行对象协议发送

    Register reg = new Register();reg.Name = txtName.Text;reg.EMail = txtEMail.Text;channel.Send(reg);

运行效果

下载代码:Code

总结

通过Beetle的协议分析器可以简单地解决TCP粘包问题的同时还可以很灵活地支持不同的协议,在后面的章节里会讲述一下如何扩展一个消息配适器实处理.net二制序充列,XML序列化,prorobuf,amf3等数据对象.

Beetle在TCP通讯中使用协议分析器和自定义协议对象相关推荐

  1. Beetle在Tcp通讯中使用Protobuf

    Protobuf是google制定的一种对象序列化格式,而在.net下的实现有protobuf-net.而protobuf-net在序列化方面有着出色的性能,效率是.net二进制序列化几倍,而序列化后 ...

  2. TCP通讯中:客户端软件如何指定本地端口号?

    TCP通讯中:客户端如何指定软件的本地端口号? 最近在Socket 通讯中用 Socket完成了对客户端 接收服务端信息以及 往服务端发送信息的功能.具体方法介绍如下: 通过Load方法 加载到指定的 ...

  3. 网络原理 | TCP/IP中的连接管理机制 重要协议与核心机制

    应用层.传输层.网络层.数据链路层.物理层 一.应用层协议 应用层 是程序猿最最经常打交道的一层 其他四层,都是操作系统.驱动.硬件,实现好了的,咱们不需要管 (除非你是系统工程师,驱动开发工程师-- ...

  4. php自定义tcp协议,如何实现自定义协议?

    一个能够解析和封装hqts协议的客户端: 一个能够解析hqts且能够对hqts协议的某个字段的sddsdd/assdsdsds/sddsdsds.html进行解析(包括转发)的服务器. 可以拿http ...

  5. Silverlight使用RSA加密socket tcp通讯数据

    在tcp通讯中为了数据安全在某些情况下对数据进行加密传输是很有必要的,可惜的是MS并没有为Silverlight提供一些标准的加密功能实现.如果你想在Silverlight中使用RSA或DES这些标准 ...

  6. 在网络通讯中应用Protobuf

    Protobuf的设计非常适用于在网络通讯中的数据载体,它序列化出来的数据量少再加上以K-V的方式来存储数据,对消息的版本兼容性非常强:还有一个比较大的优点就是有着很多的语言平台支持.下面讲解一下如何 ...

  7. TCP通信中的三次握手与四次挥手

    下图是一次TCP通讯的时序图 TCP通讯时序 在这个例子中,首先客户端主动发起连接.发送请求,然后服务器端响应请求,然后客户端主动关闭连接.两条竖线表示通讯的两端,从上到下表示时间的先后顺序,注意,数 ...

  8. 用委托的方法调用TCP通讯指令列表

    需求:TCP通讯中客户端与服务端交互会有若干中指令,例如完成一个客户度登录过程,必须先建立握手连接,然后登录,假设服务端规定这个过程中,握手连接必须先建立起来,然后才能登录,不得越级.如何让程序顺序执 ...

  9. 【Win10 UWP】URI Scheme(二):自定义协议的处理和适用场景

    上一篇提到Windows Store协议的使用,其实Windows Store协议仅是系统内建的一种协议规则.我们也可以自己定义一套规范的URI-Scheme,除了可以给其他App调用外,本应用也可以 ...

最新文章

  1. linux下挂载移动硬盘
  2. 基于vue2 + vue-router + vuex 构建的一个新闻类大型单页面应用 —— 今日头条
  3. 云幸福–如何在几分钟内安装新的OpenShift Container Platform 3.7
  4. 两端分散对齐怎么设置_Word文字很难对齐?用这4个方法,2秒可对齐所有文字!...
  5. Linux快速计算MD5和Sha1命令
  6. 漫步数理统计二十二——二项及相关分布
  7. 拉起支付宝个人转账填备注_支付宝转错钱给别人,我居然要回来了!
  8. java加vue实例_Vue.Js及Java实现文件分片上传代码实例
  9. 【推荐实践】Flink 状态(State)管理在推荐场景中的应用
  10. Pytorch nn.BCEWithLogitsLoss()的简单理解与用法
  11. mongo go 查询指定字段_使用PyMongo查询MongoDB数据库!
  12. 面向对象——类设计(七)
  13. 如何将php网页打印成pdf,新技能!如何把网页打印成pdf文件?
  14. HTML实例--制作表单
  15. mysql 磁盘满_mysql磁盘满了如何恢复
  16. WebViewJavascriptBridge
  17. 通过SYNERGY 将多台设备串联起来,只需要一副键盘便能控制
  18. 实现用户自定义表单,自定义工作流
  19. chrom中如何跳过debugger
  20. Vmware 自适应分辨率设置

热门文章

  1. SDNU 1300.转圈游戏(快速幂)
  2. 如何简单的测试kubernetes的dns add-ons是否工作正常?
  3. 使用Preplot批量将ascii文件转为二进制文件
  4. 菜单点击展开,超过四个则进行向右滑动显示demo
  5. 大家看看这个参数inctype你是否使用过?我做了以下测试,欢迎拍砖!
  6. xcode 左侧导航栏 no finder results 问题的解决方法
  7. rac下重做控制文件
  8. 如何知道 CPU 是否支持虚拟化技术(VT)
  9. Oracle学习操作(6)函数与存储过程
  10. 【Java每日一题】20170309