Netty 学习(三):通信协议和编解码
Netty 学习(三):通信协议和编解码
作者: Grey
原文地址:
无论使用 Netty 还是原生 Socket 编程,都可以实现自定义的通信协议。
所谓协议就是:客户端和服务端商量好,每一个二进制数据包中的每一段字节分别代表什么含义的规则。
有了规则,在服务端和客户端就可以通过这个设置好的规则进行二进制和对象的转换。
通信协议格式可以参考如下格式

每个部分的说明如下
魔数:用来标识这个数据包是否遵循我们设计的通信协议,类似 Java 字节码开头的4字节:0xcafebabe
版本标识:用来标识这个协议是什么版本,用于后续协议的升级
序列化算法:用于标识这个协议的数据包使用什么序列化算法,比如:JSON,XML等
指令:用于标识这个数据在收到后应该使用什么处理逻辑。
数据长度&数据内容:不赘述
定好格式以后,
接下来我们可以约定双方的序列化方法,这里我们可以用 JSON 序列化/反序列化 为例,其他格式的类似。
使用 Gson 可以很方便将 JSON 字符串和对象进行互转:
private static final Gson gson = new Gson();
// 序列化
public byte[] serialize(Object object) {
return gson.toJson(object).getBytes(UTF_8);
}
// 反序列化
public <T> T deserialize(Class<T> clazz, byte[] bytes) {
return gson.fromJson(new String(bytes, UTF_8), clazz);
}
实现了对象和字节数组的互转以后,我们需要实现字节数组和 Netty 通信载体 ByteBuf 的互转,包括如下两个方法
ByteBuf 编码(数据包)
上述编码方法需要做如下几个事情
分配 ByteBuf (分配一块内存区域,Netty 会直接创建一个堆外内存)
按照协议获取数据包对应的内容
严格按照协议规定的字节数填充到 ByteBuf 中
数据包 解码(ByteBuf byteBuf)
上述解码方法主要做如下几件事情
校验魔数
校验版本号
如果严格按照规范传输的 ByteBuf,上述两步校验一定是通过的,可以直接跳过。
获取序列化算法,指令和数据包长度,并将数据内容转换成字节数组
将字节数组转换成对应的数据包对象。
因为不同的数据包内容有所不一样,所以应该设置一个抽象类,由各个子类实现具体数据包的内容。
package protocol;
import lombok.Data;
/**
* 数据包抽象类
*
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/15
* @since
*/
@Data
public abstract class Packet {
/**
* 协议版本
*/
private Byte version = 1;
/**
* 指令,由子类实现
*
* @return
*/
public abstract Byte getCommand();
}
对于一个具体的操作,比如登录操作,它需要的数据包需要继承并实现这个抽象类的抽象方法。
package protocol;
import lombok.Data;
import static protocol.Command.LOGIN_REQUEST;
/**
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/15
* @since
*/
@Data
public class LoginRequestPacket extends Packet {
// 登录操作需要的数据内容包括如下三个
private Integer userId;
private String username;
private String password;
@Override
public Byte getCommand() {
return LOGIN_REQUEST;
}
}
对于调用者来说,只需要使用LoginRequestPacket即可,无须关注其底层的编码和解码工作。伪代码如下
func() {
LoginRequestPacket loginRequestPacket = new LoginRequestPacket();
loginRequestPacket.setVersion(((byte) 1));
loginRequestPacket.setUserId(123);
loginRequestPacket.setUsername("zhangsan");
loginRequestPacket.setPassword("password");
// 编码
ByteBuf byteBuf = 封装好的编解码工具类.编码(loginRequestPacket);
// 解码
Packet decodedPacket = 封装好的编解码工具类.解码(byteBuf);
// 序列化成我们需要的对象
序列化和反序列化工具类.序列化(decodedPacket);
}
完整代码见:hello-netty
本文所有图例见:processon: Netty学习笔记
更多内容见:Netty专栏
参考资料
Netty 学习(三):通信协议和编解码的更多相关文章
- Netty游戏服务器之四protobuf编解码和黏包处理
我们还没讲客户端怎么向服务器发送消息,服务器怎么接受消息. 在讲这个之前我们先要了解一点就是tcp底层存在粘包和拆包的机制,所以我们在进行消息传递的时候要考虑这个问题. 看了netty权威这里处理的办 ...
- Netty学习三:线程模型
1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...
- FFmpeg 学习(五):FFmpeg 编解码 API 分析
在上一篇文章 FFmpeg学习(四):FFmpeg API 介绍与通用 API 分析 中,我们简单的讲解了一下FFmpeg 的API基本概念,并分析了一下通用API,本文我们将分析 FFmpeg 在编 ...
- Netty学习(三)-Netty重要接口讲解
上一节我们写了一个HelloWorld,对于Netty的运行有了一定的了解,知道Netty是如何启动客户端和服务器端.这一节我们简要的讲解一下几个重要的接口,初步探讨Netty的运行机制,当然刚学Ne ...
- Netty学习(三)高性能之ByteBuf源码解析
原文链接: https://juejin.im/post/5db8ea506fb9a02061399ab3 Netty 的 ByteBuf 类型 Pooled(池化).Unpooled(非池化) Di ...
- 【转】Netty系列之Netty编解码框架分析
http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称 ...
- Netty系列之Netty编解码框架分析
1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decod ...
- Netty 编解码技术 数据通信和心跳监控案例
Netty 编解码技术 数据通信和心跳监控案例 多台服务器之间在进行跨进程服务调用时,需要使用特定的编解码技术,对需要进行网络传输的对象做编码和解码操作,以便完成远程调用.Netty提供了完善,易扩展 ...
- RocketMq通信协议格式及编解码 (源码分析)
一.RocketMq broker服务器与客户端的网络通信是基于netty4.x实现的,重点分析 RocketMq设计的通信协议及对应的编解码 开发. 名字解释 ...
随机推荐
- 排名前三——python 开源 IDE
写在前面的一些P话: Python无处不在 ,似乎它支持从主要网站到桌面实用程序到企业软件的所有功能. Python已经被用来编写流行的软件项目,如dnf / yum,OpenStack,OpenSh ...
- React技巧之导入组件
正文从这开始~ 总览 在React中,从其他文件中导入组件: 从A文件中导出组件.比如说,export function Button() {} . 在B文件中导入组件.比如说,import {But ...
- 生成RSA密钥的方法[转载]
openssl genrsa -des3 -out privkey.pem 2048 这个命令会生成一个2048位的密钥,同时有一个des3方法加密的密码,如果你不想要每次都输入密码,可以改成(测试常 ...
- 对象数组和对象对象数组的for-each循环
对象数组的声明 类名称 对象数组名[] = null: 对象数组名 = new 类名称[长度] 定义并开辟数组 类名称 对象数据名[] = new 类名称[长度]; 在声明一个对象数组后,必须对每个数 ...
- Properties集合中的方法store和Properties集合中的方法load
Properties集合中的方法store public class Demo01Properties { public static void main(String[] args) throws ...
- java,接口
package Demo.oop.APP.Demo07; //interface 定义接口的关键字:接口都需要实现类 public interface UserService { //接口中的所有的定 ...
- k8s+crio+podman搭建集群
前言 在传统的k8s集群中,我们都是使用docker engine做为底层的容器管理软件的,而docker engine因为不是k8s亲生的解决方案,所以实际使用中会有更多的分层.之前我们也讲过,k8 ...
- ElementUI嵌套页面及关联增删查改实现
@ 目录 前言 一.ElementUI如何在原有页面添加另外一个页面并实现关联增删查改? 二.实现步骤 1.ElementUI代码 2.思路:很简单 1.1 首先通过el-row.el-col.el- ...
- 移动web开发01
pc端的支持情况.IE9以下的版本就会全军覆没.移动端就不会出现版本支持问题. 因为第一个孩子是p,但是他又是在span里面选,所以根本选不出来,报错.改成第二个孩子才可以选出来. 这样就可以选出sp ...
- OC高仿iOS网易云音乐AFNetworking+SDWebImage+MJRefresh+MVC+MVVM
效果 因为OC版本大部分截图和Swift版本一样,所以就不再另外截图了. 列文章目录 因为目录比较多,每次更新这里比较麻烦,所以推荐点击到主页,然后查看iOS云音乐专栏. 目简介 这是一个使用OC语言 ...