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. gitlab和jenkins做持续集成构建教程

    背景介绍 上一个轮回,我花了三篇文章的时间着重向大家介绍了在条件有限的情况下,如果优雅地进行前端发版和迭代.庆七一,热烈庆祝香港回归,人民生活水平越来越好,昨天上午我自掏腰包买了台服务器,决定由冷兵器 ...

  2. 函数式(Functional)接口

    public class LambdaTest2 { @Test public void test1(){ happyTime(500, new Consumer<Double>() { ...

  3. 选择结构-扩展if-else语句和练习用if语句实现考试成绩划分

    判断语句3--if..else if...else if语句第三种格式: if...else if ...else if (判断条件1) { 执行语句1; } else if (判断条件2) { 执行 ...

  4. 2022-7-13 java_1 第七组 刘昀航

    @ 目录 前言 一.一些基本的指令 二.java 1.java的三个版本 2.java特点 3.运行一个java程序 三.java的数据类型 1.java基本数据类型 2.强制转换的原理 3.八种基本 ...

  5. String类型函数传递问题

    String类型函数传递问题 问题 以前没有注意过的一个问题, 最近在使用String类型作为函数入参的时候, 发现函数内对于String类型的改变并不会影响到外层调用对象本身; 结论 (先说结论) ...

  6. 4-5 Spring Boot

    1. 关于Spring Boot Spring Boot是Spring官方的一个产品,其本质上是一个基于Maven的.以Spring框架作为基础的进阶框架,很好的支持了主流的其它框架,并默认完成了许多 ...

  7. 作业二、安装CentOS7.9

    一.安装环境 1.VMware Workstation 16 Pro 2.CentOS7.9 二.部署系统 步骤1.进入VMware,点击创建新的虚拟机 步骤2.进入新建虚拟机向导,选择典型(推荐) ...

  8. 可变参数和Collections集合工具类

    可变参数 /** * 可变参数:jdk1.5后出现的新特性 * 使用前期: * 当方法的参数列表数据类型已经确定的时候但是参数的个数不确定的时候就可以使用可变参数 * 使用格式:定义方法的时候使用 * ...

  9. js屏蔽浏览器默认事件

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  10. YII自定义第三方扩展

    cat.php <?php /** * Created by PhpStorm. * Date: 2016/5/25 * Time: 15:23 */ namespace vendor\anim ...