Netty 学习(三):通信协议和编解码

作者: Grey

原文地址:

博客园:Netty 学习(三):通信协议和编解码

CSDN:Netty 学习(三):通信协议和编解码

无论使用 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 编码(数据包)

上述编码方法需要做如下几个事情

  1. 分配 ByteBuf (分配一块内存区域,Netty 会直接创建一个堆外内存)

  2. 按照协议获取数据包对应的内容

  3. 严格按照协议规定的字节数填充到 ByteBuf 中

数据包 解码(ByteBuf byteBuf)

上述解码方法主要做如下几件事情

  1. 校验魔数

  2. 校验版本号

  3. 如果严格按照规范传输的 ByteBuf,上述两步校验一定是通过的,可以直接跳过。

  4. 获取序列化算法,指令和数据包长度,并将数据内容转换成字节数组

  5. 将字节数组转换成对应的数据包对象。

因为不同的数据包内容有所不一样,所以应该设置一个抽象类,由各个子类实现具体数据包的内容。

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 即时聊天实战与底层原理

深度解析Netty源码

Netty 学习(三):通信协议和编解码的更多相关文章

  1. Netty游戏服务器之四protobuf编解码和黏包处理

    我们还没讲客户端怎么向服务器发送消息,服务器怎么接受消息. 在讲这个之前我们先要了解一点就是tcp底层存在粘包和拆包的机制,所以我们在进行消息传递的时候要考虑这个问题. 看了netty权威这里处理的办 ...

  2. Netty学习三:线程模型

    1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...

  3. FFmpeg 学习(五):FFmpeg 编解码 API 分析

    在上一篇文章 FFmpeg学习(四):FFmpeg API 介绍与通用 API 分析 中,我们简单的讲解了一下FFmpeg 的API基本概念,并分析了一下通用API,本文我们将分析 FFmpeg 在编 ...

  4. Netty学习(三)-Netty重要接口讲解

    上一节我们写了一个HelloWorld,对于Netty的运行有了一定的了解,知道Netty是如何启动客户端和服务器端.这一节我们简要的讲解一下几个重要的接口,初步探讨Netty的运行机制,当然刚学Ne ...

  5. Netty学习(三)高性能之ByteBuf源码解析

    原文链接: https://juejin.im/post/5db8ea506fb9a02061399ab3 Netty 的 ByteBuf 类型 Pooled(池化).Unpooled(非池化) Di ...

  6. 【转】Netty系列之Netty编解码框架分析

    http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称 ...

  7. Netty系列之Netty编解码框架分析

    1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decod ...

  8. Netty 编解码技术 数据通信和心跳监控案例

    Netty 编解码技术 数据通信和心跳监控案例 多台服务器之间在进行跨进程服务调用时,需要使用特定的编解码技术,对需要进行网络传输的对象做编码和解码操作,以便完成远程调用.Netty提供了完善,易扩展 ...

  9. RocketMq通信协议格式及编解码 (源码分析)

    一.RocketMq broker服务器与客户端的网络通信是基于netty4.x实现的,重点分析  RocketMq设计的通信协议及对应的编解码 开发.         名字解释           ...

随机推荐

  1. vmware修改虚拟机网卡mac地址

    选中"虚拟机" 右键 "设置",然后选中"网络适配器",然后点击"高级",设置"MAC地址"

  2. java中AOP的环绕通知

    pom.xml <dependencies> <dependency> <groupId>org.springframework</groupId> & ...

  3. ELK 日志分析系统的部署

    一.ELK简介 ElasticSearch介绍Elasticsearch是一个基于Lucene的搜索服务器. 它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口. Elasti ...

  4. NOI / 1.4编程基础之逻辑表达式与条件分支讲解-02:输出绝对值

    02:输出绝对值 总时间限制: 1000ms 内存限制: 65536kB 题目: 描述 输入一个浮点数,输出这个浮点数的绝对值. 输入 输入一个浮点数,其绝对值不超过10000. 输出 输出这个浮点数 ...

  5. Running Median_via牛客网

    题目 链接:https://ac.nowcoder.com/acm/contest/28886/1002 来源:牛客网 时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C++ 65536K, ...

  6. websocket、socket、http对比

    简介 在之前的理解中,讲述了socket.websocket等相关的理解,本文就socket.websocket.http理解一下其对应的联系和区别. HTTP 协议 http 为短连接:客户端发送请 ...

  7. js for和while两种99乘法表

    <script type="text/javascript"> for(var i=1; i<=9; i++) { for(var j=1; j<=i;j+ ...

  8. linux服务器监控脚本

    #!/bin/bash #获取cpu使用率 cpuUsage=`top -n 1 | awk -F '[ %]+' 'NR==3 {print $2}'` #获取磁盘使用率 data_name=&qu ...

  9. NFS 服务器配置(Ubuntu)

    # NFS 服务器配置(Ubuntu 20.0) # 1.配置网络环境 # NFS 的客户端和服务端必须在同一局域网 # 2.在服务器上安装nfs sudo apt-get install nfs-c ...

  10. 利用MySQL Router构建读写分离MGR集群

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 目录 1. 部署MySQL Router 2. 启动mysqlrouter服务 3. 确认读写分离效果 4. 确认只读负载 ...