当前位置: 首页 > article >正文

Netty初学五 客户端与服务端通信协议编解码

一、客户端与服务端的通信协议

        1.客户端与服务端的通信是基于tcp通信的数据包格式均为二进制,协议指的是客户端和服务端事先商量好的,每一个二进制包中每一段字节分别代表什么含义。

        简单的登录指令:

        2.客户端与服务端的通信:

                客户端把一个java对象按照通信协议转换为二进制数据包

                通过网络把这段二进制数据包发送到服务端,在传送的过程中是由tcp/ip协议负责数据的传输

                服务端接收到数据之后,按照协议取出二进制数据包中的相应字段包装成java对象

                服务端处理完之后,如果需要生成响应会按照同样的流程进行

        3.通信协议的设计:

        第一个字段魔数,通常情况下是固定的几个字节,该字段的作用是服务端可以根据这个字段的信息进行比对,可以判断出这个数据包并非遵循自定义协议的,即无效的数据包

        第三个字段的序列化算法表示如何将java对象转换成二进制数据以及如何将二进制数据转换成java对象

        第五个字段表示的数据长度,占4字节

       4.通信协议的实现:

                编码:将java对象根据协议封装成二进制数据包,解码反之

                java对象:

@Data
 public abstract class Packet {
/**
 * 协议版本
*/
 private Byte version = 1;

//指令
 public abstract Byte getCommand();
}

                所有的指令数据包都必须实现这个方法

                定义登录请求数据包:

public interface Command {
Byte LOGIN_REQUEST = 1;
}
@Data
 public class LoginRequestPacket extends Packet {
private Integer userId;
private String username;
private String password;
@Override
 public Byte getCommand() {
return LOGIN_REQUEST;
}
}

                上述代码示例定义了3个字段,分别是用户id 用户名和密码并且覆盖了getCommand方法

        以上过程为java对象的定义,可以根据一种规则把一个java对象转换成二进制数据,即java对象的序列化

                序列化:

public interface Serializer {
/**
 * 序列化算法
*/
 byte getSerializerAlgorithm();
/**
  * Java 对象转换成二进制数据
     */
    byte[] serialize(Object object);
    /**
     * 二进制数据转换成Java对象
     */
    <T> T deserialize(Class<T> clazz, byte[] bytes);
}

        serialize()方法将java对象转换成字节数组,deserialize()方法将字节数组转换成java对象

        json序列化方式:

public interface SerializerAlgorithm {
    /**
     * JSON序列化标识
     */
    byte JSON = 1;
}
public class JSONSerializer implements Serializer {
    @Override
    public byte getSerializerAlgorithm() {
        return SerializerAlgorithm.JSON;
    }
    @Override
    public byte[] serialize(Object object) {
        return JSON.toJSONBytes(object);
    }
    @Override
    public <T> T deserialize(Class<T> clazz, byte[] bytes) {
        return JSON.parseObject(bytes, clazz);
    }
}

        5.封装成二进制数据的过程:

 private static final int MAGIC_NUMBER = 0x12345678;
public ByteBuf encode(Packet packet) {
// 1. 创建 ByteBuf 对象
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
// 2. 序列化 Java 对象
byte[] bytes = Serializer.DEFAULT.serialize(packet);
// 3. 实际编码过程
byteBuf.writeInt(MAGIC_NUMBER);
byteBuf.writeByte(packet.getVersion());
byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm());
byteBuf.writeByte(packet.getCommand());
byteBuf.writeInt(bytes.length);
byteBuf.writeBytes(bytes);
return byteBuf;
}

        6.解析java对象的过程:

 public Packet decode(ByteBuf byteBuf) {
    // 跳过魔数
    byteBuf.skipBytes(4);
    // 跳过版本号
    byteBuf.skipBytes(1);
    // 序列化算法标识
    byte serializeAlgorithm = byteBuf.readByte();
    // 指令
    byte command = byteBuf.readByte();
    // 数据包长度
    int length = byteBuf.readInt();
    byte[] bytes = new byte[length];
    byteBuf.readBytes(bytes);
    Class<? extends Packet> requestType = getRequestType(command);
    Serializer serializer = getSerializer(serializeAlgorithm);
    if (requestType != null && serializer != null) {
    return serializer.deserialize(requestType, bytes);
}
return null;
}


http://www.kler.cn/a/537438.html

相关文章:

  • 自动驾驶---聊聊传统规控和端到端
  • 绿色工厂的好处
  • 使用page assist浏览器插件结合deepseek-r1 7b本地模型
  • 离线统信系统的python第三方库批量安装流程
  • 软件设计模式
  • H266/VVC 环路滤波中去块滤波 DF 技术
  • JUnit 5 条件测试注解详解
  • 论文阅读--LlaVA
  • python中的flask框架
  • C#中深度解析BinaryFormatter序列化生成的二进制文件
  • WebSocket connection failed 解决
  • 2024中国行政区划多边形矢量数据(含有十段线)仅供学习
  • 活动预告 |【Part 1】Microsoft 安全在线技术公开课:通过扩展检测和响应抵御威胁
  • 即梦(Dreamina)技术浅析(六):多模态生成模型
  • golang使用sqlite3,开启wal模式,并发读写
  • AD域控粗略了解
  • DeepSeek+AnythingLLM生成攻防演练方案
  • [权限提升] Linux 提权 维持 — 系统错误配置提权 - Sudo 滥用提权
  • 微信小程序案例1——制作猫眼电影底部标签导航栏
  • 网络安全ITP是什么 网络安全产品ips
  • C++轻量级桌面GUI库FLTK
  • 图文并茂-jvm内存模型
  • GaussDB对象权限的注意事项
  • 【再谈设计模式】状态模式~对象行为的状态驱动者
  • 计算机视觉语义分割——Attention U-Net(Learning Where to Look for the Pancreas)
  • 【算法】动态规划专题⑨ —— 二维费用背包问题 python