Netty学习--编/解码器

在netty进行消息的发送和读取时,都会进行一次数据格式的转化。在发送消息时,会把消息转化成字节,便于网络传输;读取时,再将字节转化成相应的对象,而这种数据的转化便是通过编码器和解码器来实现的。

1.编码器

Netty主要提供了两种类型的编码器:

MessageToMessageEncoder     将消息对象编码成消息对象

MessageToByteEncoder    将消息对象编码成字节码(网络传输时常用)

这两中编码器都只需要继承相应的父类,并通过泛型来指定想要转化的消息类型

具体代码实现:

MessageToMessageEncoder

/**
 * 自定义编码器,将Integet转化成String类型
 *
 * @author shuchang
 * @version 1.0
 * @date 2020/8/30 23:37
 */
public class Encoder extends MessageToMessageEncoder<Integer> {

    @Override
    protected void encode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
        out.add(String.valueOf(msg));
    }
}

MessageToByteEncoder

/**
 * 自定义编码器,将按照自定义的协议封装好的消息转化成二进制进行网络传输
 *
 * @author shuchang
 * @version 1.0
 * @date 2020/8/30 23:37
 */
public class MyMessageEncoder extends MessageToByteEncoder<MyMessageProtocal> {

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, MyMessageProtocal myMessageProtocal, ByteBuf byteBuf) throws Exception {
        byteBuf.writeInt(myMessageProtocal.getLength());
        byteBuf.writeBytes(myMessageProtocal.getContent());
    }
}

自定义的编码器可以通过pipeline.addFirst()或addLast()方法添加到管道的处理器集合中,进行业务处理。

2.解码器

Netty同样也提供了两种解码器类型

ByteToMessageDecoder    解码字节到消息

MessageToMessageDecoder      解码消息到消息Na

解码器主要负责从通道另一端进行读取数据时,对数据进行解析的工作。

ByteToMessageDecoder

继承这个类后,我们主要是需要重写他的decode方法,根据我们自定义的协议,对获取的byte[]进行解析(编码和解码过程必须遵循一致的协议,否则无法解析成功)

具体代码实现:

public class MyMessageDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {

        //获取文本长度
        int length = byteBuf.readInt();

        //声明一个长度为length的byte数组,并读取响应长度的数据
        byte[] content = new byte[length];
        byteBuf.readBytes(content);

        //解析完毕后,重新封装进自定义的协议中
        MyMessageProtocal messageProtocal = new MyMessageProtocal();
        messageProtocal.setLength(length);
        messageProtocal.setContent(content);

        //将封装好的协议添加到list中,传递到下一个handler进行处理
        list.add(messageProtocal);

    }
}

由于在配置启动类时,没有配置TCP_NODELAY属性,TCP协议会基于Nagle算法将多个数据块合并发送,就会导致TCP粘包和拆包的问题。

什么是TCP粘包/拆包?

1.D1和D2正好满足缓冲区大小,服务端收到两个独立的数据包,无粘包拆包问题

2.基于tcp协议发送数据包时D1和D2合并成一个数据块发送到服务端,出现TCP粘包

3.服务端第一次收到D1和部分D2,第二次收到剩余部分D2,出现TCP拆包,这是因为TCP进行合并发送时,缓冲区大小不足以承载两个数据包,因此D2被截断成两部分发送

4.服务端第一次收到部分D1,第二次收到剩余D1和全部D2,这是因为D1文件大小过大,缓冲区放不下,D1分段发送

处理TCP粘包拆包问题

解决方案:

1.客户端在发送数据包的时候,每个包都固定长度,比如1024个字节大小,如果客户端发送的数据长度不足1024个字节,则通过补充空格的方式补全到指定长度;

2.客户端在每个包的末尾使用固定的分隔符,例如\r\n,如果一个包被拆分了,则等待下一个包发送过来之后找到其中的\r\n,然后对其拆分后的头部部分与前一个包的剩余部分进行合并,这样就得到了一个完整的包;(通过DelimiterBasedFrameDecoder处理分隔符)

3.将消息分为头部和消息体,在头部中保存有当前整个消息的长度,只有在读取到足够长度的消息之后才算是读到了一个完整的消息;

4.通过自定义协议进行粘包和拆包的处理。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值