netty中实现自定义协议

本文介绍了一种基于TCP/IP的自定义网络通信协议的设计与实现,重点讲解了协议中的关键要素,包括魔数、版本号、序列化算法、指令类型等,并通过Netty框架提供了具体的编码和解码实现。

为什么需要协议
TCP/IP 中消息传输基于流的方式,没有边界。协议的目的就是划定消息的边界,制定通信双方要共同遵守的通信规则

自定义协议要素
魔数,用来在第一时间判定是否是无效数据包
版本号,可以支持协议的升级
序列化算法,消息正文到底采用哪种序列化反序列化方式,可以由此扩展,例如:json、protobuf、hessian、jdk
指令类型,是登录、注册、单聊、群聊… 跟业务相关
请求序号,为了双工通信,提供异步能力
正文长度
消息正文

代码

package cn.itcast.protocol;

import cn.itcast.config.Config;
import cn.itcast.message.LoginRequestMessage;
import cn.itcast.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

@Slf4j
@ChannelHandler.Sharable
/**
 * 必须和 LengthFieldBasedFrameDecoder 一起使用,确保接到的 ByteBuf 消息是完整的
 */
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
    @Override
    public void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {
        ByteBuf out = ctx.alloc().buffer();
        // 1. 4 字节的魔数
        out.writeBytes(new byte[]{1, 2, 3, 4});
        // 2. 1 字节的版本,
        out.writeByte(1);
        // 3. 1 字节的序列化方式 jdk 0 , json 1
        out.writeByte(Config.getSerializerAlgorithm().ordinal());
        // 4. 1 字节的指令类型
        out.writeByte(msg.getMessageType());
        // 5. 4 个字节
        out.writeInt(msg.getSequenceId());
        // 无意义,对齐填充
        out.writeByte(0xff);
        // 6. 获取内容的字节数组
        byte[] bytes = Config.getSerializerAlgorithm().serialize(msg);
        // 7. 长度
        out.writeInt(bytes.length);
        // 8. 写入内容
        out.writeBytes(bytes);
        outList.add(out);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int magicNum = in.readInt();
        byte version = in.readByte();
        byte serializerAlgorithm = in.readByte(); // 0 或 1
        byte messageType = in.readByte(); // 0,1,2...
        int sequenceId = in.readInt();
        in.readByte();
        int length = in.readInt();
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);

        // 找到反序列化算法
        Serializer.Algorithm algorithm = Serializer.Algorithm.values()[serializerAlgorithm];
        // 确定具体消息类型
        Class<? extends Message> messageClass = Message.getMessageClass(messageType);
        Message message = algorithm.deserialize(messageClass, bytes);
//        log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
//        log.debug("{}", message);
        out.add(message);
    }

}

服务端添加

		//...
        MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
		//...

		//...
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                //...
				ch.pipeline().addLast(MESSAGE_CODEC);
				//...
                }
            });
                //...
		//...

<think>嗯,用户问的是如何在Netty实现自定义协议的四次握手。首先,我需要回忆一下Netty的基本架构和处理协议的方式。Netty通常使用ChannelHandler来处理入站和出站的数据,所以可能需要自定义编码解码器。 四次握手可能指的是类似TCP的三次握手,但这里多了一次。可能是在应用层协议中需要更多的交互步骤。比如,客户端发送请求,服务端响应,客户端再确认,服务端最终确认之类的流程。需要明确四次握手的具体步骤和每个步骤的消息格式。 接下来,我需要考虑如何定义协议的数据结构。可能需要自定义消息对象,包含类型、长度、数据等字段。然后编写编码器和解码器来处理ByteBuf和消息对象之间的转换。 然后,处理握手的逻辑。可能需要使用状态机来管理握手的不同阶段,比如初始状态、收到第一次请求、发送响应、等待确认等。每个状态转换时处理相应的消息,并发送下一个步骤的消息。 另外,Netty的ChannelPipeline中需要添加自定义的Handler,处理握手过程中的各个步骤。可能需要使用SimpleChannelInboundHandler来处理特定类型的消息,并在处理完成后移除自己或者切换到下一个状态的Handler。 还要考虑异常处理和超时处理,确保握手过程的健壮性。比如,如果某个步骤超时,应该关闭连接或者发送错误消息。 可能还需要使用Future或者Promise来处理异步操作,比如在发送握手消息后等待对方的响应,或者处理握手完成后的后续操作。 最后,测试部分可能需要编写客户端和服务端的示例代码,验证四次握手是否正确完成,并处理各种边界情况。 现在需要将这些思路整理成一个结构化的回答,包括步骤和示例代码。然后生成相关问题,比如具体的编码解码实现、状态机管理、异常处理等。</think>在Netty实现自定义协议的4次握手需要结合协议设计、编码解码器和状态机管理,以下是实现思路和示例代码: 1. **协议设计** ```java // 自定义消息类型 public class HandshakeMessage { private byte type; // 消息类型(请求/响应/确认等) private byte[] data; // 载荷数据 // getter/setter省略 } ``` 2. **编码解码器** ```java // 编码器 public class HandshakeEncoder extends MessageToByteEncoder<HandshakeMessage> { @Override protected void encode(ChannelHandlerContext ctx, HandshakeMessage msg, ByteBuf out) { out.writeByte(msg.getType()); out.writeBytes(msg.getData()); } } // 解码器 public class HandshakeDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { if (in.readableBytes() < 1) return; byte type = in.readByte(); byte[] data = new byte[in.readableBytes()]; in.readBytes(data); out.add(new HandshakeMessage(type, data)); } } ``` 3. **握手状态机** ```java public class HandshakeHandler extends SimpleChannelInboundHandler<HandshakeMessage> { private enum State { INIT, SENT_REQUEST, SENT_RESPONSE, SENT_CONFIRM } private State state = State.INIT; @Override public void channelActive(ChannelHandlerContext ctx) { // 初始发送握手请求 HandshakeMessage request = new HandshakeMessage((byte)0x01, "ClientHello".getBytes()); ctx.writeAndFlush(request); state = State.SENT_REQUEST; } @Override protected void channelRead0(ChannelHandlerContext ctx, HandshakeMessage msg) { switch (state) { case SENT_REQUEST: if (msg.getType() == 0x02) { // 收到响应 HandshakeMessage confirm = new HandshakeMessage((byte)0x03, "ClientConfirm".getBytes()); ctx.writeAndFlush(confirm); state = State.SENT_RESPONSE; } break; case SENT_RESPONSE: if (msg.getType() == 0x04) { // 收到最终确认 System.out.println("4次握手完成"); ctx.pipeline().remove(this); // 移除握手处理器 } break; } } } ``` 4. **服务端实现** ```java public class ServerHandshakeHandler extends SimpleChannelInboundHandler<HandshakeMessage> { private enum State { WAITING_REQUEST, WAITING_CONFIRM } private State state = State.WAITING_REQUEST; @Override protected void channelRead0(ChannelHandlerContext ctx, HandshakeMessage msg) { switch (state) { case WAITING_REQUEST: if (msg.getType() == 0x01) { // 收到请求 HandshakeMessage response = new HandshakeMessage((byte)0x02, "ServerResponse".getBytes()); ctx.writeAndFlush(response); state = State.WAITING_CONFIRM; } break; case WAITING_CONFIRM: if (msg.getType() == 0x03) { // 收到确认 HandshakeMessage finalConfirm = new HandshakeMessage((byte)0x04, "ServerFinal".getBytes()); ctx.writeAndFlush(finalConfirm); System.out.println("4次握手完成"); ctx.pipeline().remove(this); } break; } } } ``` 5. **通道初始化** ```java // 客户端 pipeline.addLast(new HandshakeEncoder(), new HandshakeDecoder(), new HandshakeHandler()); // 服务端 pipeline.addLast(new HandshakeEncoder(), new HandshakeDecoder(), new ServerHandshakeHandler()); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值