SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SuperSocket与Netty之实现protobuf协议,包括服务端和客户端相关的知识,希望对你有一定的参考价值。

今天准备给大家介绍一个c#服务器框架()和一个c#客户端框架()。这两个框架的作者是园区里面的。 首先感谢他的无私开源贡献。之所以要写这个文章是因为群里经常有人问这个客户端框架要如何使用。原因在于服务端框架的文档比较多,客户端的文档比较少,所以很多c#基础比较差的人就不懂怎么玩起来。今天就这里写一个例子希望能给部分人抛砖引玉吧。

参考资料:

SuperSocket文档

我以前在开源中国的一部分文章:

这篇文章选择 来实现,选择是因为服务器有可能用的是java的netty,客户端想用SuperSocket.ClientEngine,而netty我看很多人经常用protobuf。


一、SuperSocket服务器

新建一个项目 ProtobufServer 然后添加 SuperSocket 和 protobuf 的依赖包。

添加protobuf依赖包 输入的搜索词是 Google.ProtocolBuffers
添加SuperSocket依赖包 输入搜索词是 SuperSocket,要添加两个SuperSocket.Engine 和 SuperSocket

上面的工作完成后,我们就应该来实现我们的传输协议了。传输协议打算参考netty的

* BEFORE DECODE (302 bytes)       AFTER DECODE (300 bytes)* +--------+---------------+      +---------------+* | Length | Protobuf Data |----->| Protobuf Data |* | 0xAC02 |  (300 bytes)  |      |  (300 bytes)  |* +--------+---------------+      +---------------+

Protobuf Data是protobuf的序列化结果。Length(Base 128 Varints)是表示Protobuf Data的长度。protobuf本身的序列号协议可以参考:

我们先看一下SuperSocket的看看有没有合适我们可以直接拿来用的。因为Length使用的是Base 128 Varints一种处理整数的变长二进制编码算法,所以呢内置的协议实现模板并不能直接拿来使用,所以我们只能自己来实现接口IRequestInfo和IReceiveFilter了,参考:。

这里说明一下:为什么protobuf明明序列化成Protobuf Data 了为什么还要再加一个Length来打包,因为tcp这个流发送会参数粘包、分包,如果不加个协议来解析会读取错误的数据而导致无法反序列化 Protobuf Data (自行谷歌 tcp 粘包、分包)

ProtobufRequestInfo的实现

在实现ProtobufRequestInfo之前要先来考虑一个问题,那就是我们的传输协议是长度+protobuf数据,那么我们根本就无法知道获取到的protobuf数据该如何反序列化。在官方网站提供了一种解决思路:
就是我们可以弄唯一个数据包,然后这个数据包里面必须包含一个枚举值,然后还包含了其他类型的数据包,每一个枚举值对应一个数据包,然后传送过来后,可以用分支判断来获取值。

那我们先设计一个 DefeatMessage.proto包含内容:

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

然后再把CallMessage和BackMessage补全

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

然后在我们的路径packages\Google.ProtocolBuffers.2.4.1.555\tools里面有两个工具protoc.exe 和 protogen.exe,我们可以执行下面的命令来生成我们的c#代码

protoc --descriptor_set_out=DefeatMessage.protobin --proto_path=pack --include_imports pack\DefeatMessage.proto

protogen DefeatMessage.protobin

注意路径要自己修改

如果有报Expected top-level statement (e.g. "message").这么一个错误,那就是你cmd的编码和proto的编码不一致,要改成一致。

相关文件:

生成完c#代码后,我们就要设计ProtobufRequestInfo了。这个比较简单,只要实现IRequestInfo接口。我们这里在实现接口带的属性外另加一个 DefeatMessage 和 DefeatMessage.Types.Type,其中DefeatMessage是为了存储我们解包完数据后反序列化出来的对象,Type是为了方便区分我们应该取出DefeatMessage里面的哪个值。

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

ProtobufReceiveFilter的实现

代码比较长,直接看在github上的代码
实现的注意点参考:。主要是对ss里面给我们缓存的数据流进行协议解析。

  1. readBuffer: 接收缓冲区, 接收到的数据存放在此数组里

  2. offset: 接收到的数据在接收缓冲区的起始位置

  3. length: 本轮接收到的数据的长度

  4. toBeCopied: 表示当你想缓存接收到的数据时,是否需要为接收到的数据重新创建一个备份而不是直接使用接收缓冲区

  5. rest: 这是一个输出参数, 它应该被设置为当解析到一个为政的请求后,接收缓冲区还剩余多少数据未被解析

    SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

ProtobufAppSession 的实现

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

ProtobufAppServer 的实现

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

服务器的实例启动实现

参考:

代码:

主要是接收到数据的一个方法实现,当然ss里面还带了命令模式的实现,不过这个不在本文章里面说。这里的实现了接收到不同的数据给打印出来,然后接收到CallMessage数据的话就给客户端回发一条信息

 SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

服务器的代码就到这里,可以编译运行起来看看有无错误。

二、SuperSocket.ClientEngine客户端

与服务器实现相同,先通过NuGet添加 SuperSocket.ClientEngine 和 protobuf 的依赖包。
有三个实现:

ProtobufPackageInfo的实现

把前面实现服务器时候生成的通讯数据包拷贝过来,然后和实现服务器的ProtobufRequestInfo一样,只不过这里只是实现接口IPackageInfo而已

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

ProtobufReceiveFilter的实现

代码:
这里的数据解析的实现与服务器的实现有点不同,不过下一个版本可能会统一,如果统一起来的话,那么以后数据解析就可以做成和插件一样,同时可以给服务器和客户端使用。

  1. data:也是数据缓存区

  2. rest:缓存区还剩下多少

这个实现与服务器的不同就在BufferList本身就已经有处理分包,就不需要我们自己再做处理。

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

运行主程序实现

具体实现看:

这个真的没有什么好说了。运行效果如下:
SuperSocket与Netty之实现protobuf协议,包括服务端和客户端
这里的打印信息���相对比较简单,大家可以自己下载源码来加些打印数据,让看起来更好看点。

三、java的Netty实现

既然前面提到了Netty,那就顺便实现一个简单的服务器来通讯看看。
使用的是Netty 4.x 参考资料:

Netty的实现在网络上有超级多的例子,这里就简单的介绍一下就可以,首先先生成java的通讯包代码

protoc --proto_path=pack --java_out=./ pack/DefeatMessage.proto

protoc --proto_path=pack --java_out=./ pack/BackMessage.proto

protoc --proto_path=pack --java_out=./ pack/CallMessage.proto

这几个命令要自己灵活改变们不要死死的硬搬。

生成的代码:

然后创建一个maven项目,添加Netty 和 protobuf 依赖:

<dependencies>        <dependency>            <groupId>com.google.protobuf</groupId>            <artifactId>protobuf-java</artifactId>            <version>2.6.1</version>        </dependency>        <dependency>            <groupId>io.netty</groupId>            <artifactId>netty-microbench</artifactId>            <version>4.1.0.Final</version>        </dependency>    </dependencies>

ProtobufServerHandler的实现

因为Netty里面已经有帮我们实现了protobuf的解析,所以我们不需要自己实现。我们只要继承ChannelInboundHandlerAdapter然后通过channelRead就可以拿到解析好的对象,然后转换成我们自己的类型,就可以直接使用。这里同样是实现不同类型的消息打印和CallMessage消息就回复信息给客户端。

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

ProtobufServer的实现

主要是添加已经有的编码解码和消息接收的类就可以了。

SuperSocket与Netty之实现protobuf协议,包括服务端和客户端

整个代码编写完成后,直接运行并打开我们前面的客户端进通讯发数据。运行结果如下:

当然这三个例子直接简单的说明如何使用框架来解决我们的问题,实际开发过程中肯定不只是我们例子的这么点东西,需要考虑的东西还很多,这里只是写一些可以运行起来的例子作为抛砖引玉。希望能给不懂的同学有点启发作用。谢谢您百忙中抽出时间来观看我的分享。


相关文章:



.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注


以上是关于SuperSocket与Netty之实现protobuf协议,包括服务端和客户端的主要内容,如果未能解决你的问题,请参考以下文章

Netty系列化之Google Protobuf编解码

SuperSocket源码解析之会话生命周期

netty编解码之jboss marshalling

SuperSocket

SuperSocket源码解析之开篇

基于开源SuperSocket实现客户端和服务端通信项目实战