BeetleX之TCP消息通讯Protobuf/TLS
在网络通讯应用中直接操作数据流是比较繁琐的事情,毕竟在业务层面处理的都是对象化消息;为了让网络数据操作变得更友好直观,一般都会引用序列化组件来处理网络流和对象之前的转换工作;在这里介绍组件如何使能Protobuf进行数据交互通讯。
协议定义
组件使用对象处理就不同之前HelloWorld示例一样简单操作流就可以,在这里需要进一步封装一个简单的应用协议。
|-----------------------------------------------------------------|
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 |
|----------------------------------------------------------------|
|Probobuf数据流长度,占4字节 |
|----------------------------------------------------------------|
|Protobuf数据流 |
|----------------------------------------------------------------|
以上是一个简单的应用协议,消息头4字节描述消息的长度,对应长度的数据则是Protobuf序列化对象数据。但这样的协议用在Protobuf上还是有问题,那就是无法知道这些数据对应于那个数据类型对象;所以还需要调整一下
|----------------------------------------------------------------|
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7 |
|----------------------------------------------------------------|
| Probobuf数据流长度,占4字节 |
|----------------------------------------------------------------|
| 消息类型,占4字节 |
|----------------------------------------------------------------|
| Protobuf数据流 |
|----------------------------------------------------------------|
在序列化数据流前添加了4字节用于描述对应的消息类型,对于这个类型其实可以使用2字节来描述,毕竟一个无符号的短整型可以描述6万多个消息类型了。如果想表达得更友好些可以用字符来描述消息类型,只是字符所占有的空间比较多些。
协议分析器
组件提供了FixedHeaderPacket抽象协议分析器来处理这种简单应用协议,只要继承重写两个方法即可完成。
public class ProtobufPacket : FixedHeaderPacket{static ProtobufPacket(){TypeHeaer.Register(typeof(ProtobufPacket).Assembly);}public static CustomTypeHeader TypeHeaer { get; private set; } = new CustomTypeHeader(MessageIDType.INT);public override IPacket Clone(){return new ProtobufPacket();}protected override object OnRead(ISession session, PipeStream stream){Type type = TypeHeaer.ReadType(stream);return ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(type, stream, null, null, CurrentSize - 4);}protected override void OnWrite(ISession session, object data, PipeStream stream){TypeHeaer.WriteType(data, stream);ProtoBuf.Meta.RuntimeTypeModel.Default.Serialize(stream, data);}}
分析器定义CustomTypeHeader用于管理消息类型和数据的转换,并在协议分析器静态初始化的时候把当前程序集中所有消息映射关系加载进去。
消息编码
OnWrite方法负责消息编码,写入消息类型,然后再写入Protobuf序列化后的数据流。
消息解码
OnRead方法负责消息解码, 先读取消息类型,然后再拿数据流中的数据反序列化到相应的对象。正常做法这里需要判断没有获取到正常的消息类型,没有则抛对应的异常。
通过以上简单的扩展,一个基于Protobuf的通讯应用协议就扩展完成。
定义消息
在这个示例中使用了Protobuf.net组件,用这组件在定义消息的时候还是要遵循某些规则的,接下来看一下消息的定义:
[MessageType(1)][ProtoContract]public class Register{[ProtoMember(1)]public string Name { get; set; }[ProtoMember(2)]public string EMail { get; set; }[ProtoMember(3)]public string Password { get; set; }}[MessageType(2)][ProtoContract]public class RegisterResult{[ProtoMember(1)]public bool Success { get; set; }[ProtoMember(2)]public string Message { get; set; }}
使用Protobuf.net组件需要用ProtoContract来描述一个序列化消息,并用ProtoMember来描述对应的成员属性。MessageType特性用于描述消息类型对应关系。
制定服务
针对有协议解释对象的TCP服务在处理上和基础的hello world服务差不多,只是重写接管的消息处理方法有所不同。
class Program : ServerHandlerBase
{static IServer mServer;static void Main(string[] args){mServer = SocketFactory.CreateTcpServer(new Program(), new ProtobufPacket());mServer.Options.LogLevel = LogType.Info; //mServer.Options.DefaultListen.Port=9090//mServer.Options.DefaultListen.SSL = true;//mServer.Options.DefaultListen.CertificateFile = "ssl.pfx";//mServer.Options.DefaultListen.CertificatePassword = "123456";mServer.Open();System.Threading.Thread.Sleep(-1);}protected override void OnReceiveMessage(IServer server, ISession session, object message){RegisterResult result = new RegisterResult();if (message is Register register){server.Log(LogType.Info, session, $"{session.RemoteEndPoint} 注册 {register.Name}");result.Success = true;result.Message = $"{register.Name}你已注册成功,注册邮件地址:{register.EMail}";}else{result.Success = false;result.Message = "非法请求";}session.Send(result);base.OnReceiveMessage(server, session, message);}
}
通过重写OnReceiveMessage方法来接管消息处理,在SSL处理上和之前的hello world示例是一样的配置方式。
客户端访问
组件提供了AwaiterClient对象来实现基于async/await的消息接收处理,所以在这个示例中就没有使用AsyncTcpClient这个类来处理了(AsyncTcpClient是基于事件方式接收消息在处理上相对麻烦一些)。
class Program
{static async Task Main(string[] args){var client = new AwaiterClient("localhost", 9090, new ProtobufClientPacket());while (true){Register register = new Register();Console.Write("Enter you name:");register.Name = Console.ReadLine();Console.Write("Enter you email:");register.EMail = Console.ReadLine();Console.Write("Enter you password:");register.Password = Console.ReadLine();var result = await client.ReceiveFrom<RegisterResult>(register);Console.WriteLine($"{result.Success} {result.Message}");Console.WriteLine("-".PadLeft(100, '-'));}}
}
以上代码是向服务端发送一个注册信息并等待返回输出;通过AwaiterClient的ReciveFrom<T>方法可以在发送消息后等待一个消息返回;以下示例是运行显示效果。
小结
虽然传递消息比起直接数据流操作方便很多,但如果针对每个逻辑都写请求和响应其工作也是相当繁琐的。组件有专门针对接口远程调用扩展组件
https://github.com/IKende/XRPC
下载
链接:https://pan.baidu.com/s/118Qal6kJKZ6T9tglaZT3bw
提取码:1b84
【BeetleX通讯框架代码详解】
BeetleX
开源跨平台通讯框架(支持TLS)
轻松实现高性能:tcp、http、websocket、redis、rpc和网关等服务应用
https://beetlex.io
BeetleX之TCP消息通讯Protobuf/TLS相关推荐
- 零配置Socket TCP消息通讯服务容器EC
EC全称是elastic communication,是基于c#实现的Socket网络通讯服务容器,支持windows .Net和mono.通过EC容器可以让开发人员在不了解Socket网络通讯知识和 ...
- TCP局域网 通讯 的消息发送
import java.io.*; import java.net.ServerSocket; import java.net.Socket;/*** 初学者TCP局域网 通讯 的消息发送* TCP ...
- java tcp 编程实例_Java实现基于TCP的通讯程序实例解析
Java中的TCP通信程序 TCP可以实现两台计算机之间的数据交互通信的两端,要严格区分客户端与服务端 两端通信时的步骤: 1.服务端程序,需要事先启动,等待客户端连接 2.客户端主动连接服务器端,才 ...
- QT TCP局域网通讯工具 V1.0
TCP局域网通讯工具 V1.0 局域网 一件发送消息.发送文件软件. 1.实现了发送消息.多台客户端连入服务器均可看到客户端IP地址和内容. 2.实现了客户端给服务器发送文件功能. 本文作者原创,转载 ...
- PYTHON通过TCP/IP通讯方式远程控制Epson机械臂
PYTHON通过TCP/IP通讯方式远程控制Epson机械臂 一,控制器程序(server) 程序示例 通讯函数: #定义TCP连接 Function connectSetNet #201, &quo ...
- 消息通讯之关于消息队列MQ必须了解的相关概念
目录 系统通讯方式有哪些? 消息队列的应用场景 消息队列通讯模型 常见的消息协议 AMQP MQTT ATOMP JMS 小结 系统通讯方式有哪些? RPC调用 RPC 全称 Remote Proce ...
- PowerShell收发TCP消息包
在上篇文章中,我们在PSNet包中创建了Test-TCPPort函数用于探测指定IP的指定端口是否开放,检测端口之后大多数人想到的可能就是需要通过PowerShell收发TCP消息包了,这篇文章里将会 ...
- PWA(Progressive Web App)入门系列:消息通讯
前言 serviceWorker 的能力决定它要处理的事情,网站页面的部分逻辑处理会转移到 serviceWorker 层进行处理,这里就要页面层和 serviceWorker 层进行交互来实现消息通 ...
- TCP协议通讯流程(三次握手及四次挥手)
TCP协议通讯流程(三次握手及四次挥手) 文章目录 TCP协议通讯流程(三次握手及四次挥手) 一.服务器端 二.客户端 三.三次握手四次挥手 三.具体流程 四.相关注意事项 一.服务器端 调用sock ...
最新文章
- tim计时器读出为0_高中物理 必修1 (12) 第一章 运动的描述 课时4 实验:用打点计时器测速度(1)...
- Trie实现(C++)
- vue数组对象双向绑定
- iOS 9检测QQ、微信是否安装
- 1.6 回归评估准确性的指标
- win10分辨率不能调整_笔记本win10系统调整外接显示器分辨率的方法
- 怎么看小米的去扁平化
- 一句话告诉您什么是运维?以及如何运维才能事半功倍?
- 计算机到点就有音乐怎么清除缓存垃圾,QQ音乐缓存文件在哪 QQ音乐缓存清理方法-电脑教程...
- EnvironmentNotWritableError:The current user does not have write permissions to the target...
- pyton3 with异常
- 计算机组成原理、操作系统、数据结构和计算机网络融会贯通
- systemd service unit
- 人工智能工程师一般需要学什么?
- 蓝牙及蓝牙耳机工作原理
- 研究生真正需要培养的五大能力
- 基于yolov5轻量级的学生上课姿势检测识别分析系统
- RocketMQ延迟消息的代码实战及原理分析
- 计算机关闭远程桌面,windows 远程桌面关闭 运行程序退出
- 使用JS实现俄罗斯方块游戏