Netty实现自定义通信协议

概述

在网络编程中,无论使用netty还是其它的socket通讯框架,都是通过TCP或UDP传输二进制流。发送方把要发送的对象转化成二进制流发送出去;接收方把接收到的二进制流转化为对象进行处理。 为了能让接收方和发送方能对同一个二进制流有相同的认识,双方必须提前约定好一个协议,即对象如何转化为二进制流,二进制流如何转化为对象,这样通信双方才不会产生误解。

自定义通信协议

easy-im 项目中,定义如下通信协议:

魔数:4字节,一般为固定值,本项目中使用0x88888888。一般我们的应用于某个端口对外开放,为了防止该端口被意外调用,我们可以在收到报文后,取前4个字节与魔数比对,如果不相同,则直接拒绝并关闭连接。

版本号: 1字节,一般是预留字段,为了支持协议升级(这种情况极少出现)。

序列化算法:1字节,表示如何将java对象转化为二进制数据,以及如何反序列化。

指令:1字节,表示该消息的意图,如私聊、群聊、登录等。最多支持256种指令。

数据长度:4字节,表示该字段后数据部分的长度。

数据:具体数据的内容。每种指令对应的数据是不同的。

序列化算法

本项目为了简单起见,使用json序列化算法。将Java对象转换成json字符串,再转化为二进制数据,代码如下:

首先定义Serializer接口,serialize方法用于将对象序列化为二进制数据,deSerialize方法用于将二进制反序列化成对象。getSerializerAlgorithm方法返回序列化算法。 JsonSerializer是Serializer的实现。

指令设计

定义Packet类,作为所有指令的基类,其中getCommand方法为抽象方法,需由子类实现,返回具体的指令类型。

登录指令如下,登录时需要发送userId,useName,password等信息,以及指令command:

指令类型如下:

编解码实现

定义好序列化算法和指令之后,就可以进行编解码的实现了。编码即将通信包转化为二进制;解码即将二进制转化为通信包。

编码过程比较简单,代码如下,参照注释即可明白,ByteBuf里即是最后要发送的二进制数据:

这里暂时跳过魔数和版本校验,获取到序列化算法、指令、数据长度和数据内容。根据指令我们可以知道请求类型是什么(如登录请求LoginRequestPacket、群聊请求GroupChatRequestPacket),根据序列化算法,将数据内容反序列化成目标对象,解码结束。

可以看到,编码与解码是相反的过程。

总结

基于netty作为网络通信基础组件时,我们必须要做如下几个步骤:

  • 定义通讯协议,通信双方需对此协议有一致的理解;
  • 编码,将Java对象转化为二进制;
  • 解码,将二进制转化为Java对象;
  • 业务处理

如果采用http、websocket等公有协议通信,netty提供了许多类可以实现步骤1,2,3,无需我们编码实现,只需调用相应的类和方法即可。

项目地址:github.com/sunnick/eas…

参考文档: 《netty入门实战:仿写微信IM及时通讯系统》

欢迎关注公众号:程序员顺仔

转载于:https://juejin.im/post/5c8474e0f265da2da4083cee

Java Netty 是一款高性能、异步事件驱动的网络框架,主要设计用于简化网络服务器和客户端的编程,并且能够处理高并发连接。它基于 NIO(非阻塞 I/O)技术,利用多路复用(例如 Selector)实现了对单个线程高效地管理大量并发连接的能力。Netty 框架提供了一系列高级功能,包括缓冲区管理和协议编码/解码(Codec),使得开发者可以专注于业务逻辑而无需过多关注底层网络细节。 ### Java Netty 实现 TCP 通信的基本步骤: #### 1. **构建项目** - 创建一个新的 Java 项目,在 Maven 或 Gradle 中添加相应的依赖库 `netty-all` 和 `netty-tcnative-full`。 #### 2. **配置服务端** - 定义一个服务端 `ServerBootstrap` 类型的对象,用于初始化服务端实例并绑定到特定的 IP 地址和端口。 - 使用 `ChannelPipelineFactory` 配置管道,这通常包含了接收数据、处理数据以及发送响应的过程。 - 设置必要的处理器,如 `ServerSocketChannelHandler` 负责接收新连接请求,然后创建新的 `Channel` 对象。 - 启动服务端,监听指定端口并开始接受连接。 ```java public class MyServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); // 添加你的处理器链在这里,比如定义的自定义编码器Decoder和解码器Encoder等 p.addLast(new YourCustomDecoder()); p.addLast(new YourCustomEncoder()); p.addLast("handler", new MyServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 100) .childOption(ChannelOption.SO_KEEPALIVE, true); b.bind(8080).sync().channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); } } } ``` #### 3. **配置客户端** - 定义一个客户端类,使用 `ClientBootstrap` 初始化客户端实例。 - 设置 `ChannelFutureListener` 来处理连接状态的变化。 - 发送数据到服务器并读取服务器返回的数据。 ```java public class MyClient { private final String host; private final int port; public MyClient(String host, int port) { this.host = host; this.port = port; } public void connect() throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ClientBootstrap b = new ClientBootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); // 添加你的处理器链,比如定义的自定义编码器Decoder和解码器Encoder等 p.addLast(new YourCustomDecoder()); p.addLast(new YourCustomEncoder()); p.addLast("handler", new MyClientHandler()); } }); SocketAddress remoteAddress = new InetSocketAddress(host, port); ChannelFuture f = b.connect(remoteAddress); f.syncUninterruptibly(); // 等待连接完成 // 如果需要,从这里开始发送数据和接收响应的操作 } finally { workerGroup.shutdownGracefully(); } } } ``` #### 4. **处理数据和异常** - 编写自定义的编码器和解码器,以及处理异常的逻辑。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值