美文网首页
Netty学习--编解码器框架

Netty学习--编解码器框架

作者: 何何与呵呵呵 | 来源:发表于2019-01-23 18:53 被阅读0次
什么是编解码器

如果将消息看作是对于特定的应用程序具有具体含义的结构化的字节序列—它的数据。那么编码器是将消息转换为适合于传输的格式(最有可能的就是字节流);而对应的解码器则是将网络字节流转换回应用程序的消息格式。因此,编码器操作出站数据,而解码器处理入站数据。

解码器

Netty涵盖两种类:
1.将字节解码为消息——ByteToMessageDecoder 和ReplayingDecoder;
2.将一种消息类型解码为另一种——MessageToMessageDecoder。

  • 抽象类ByteToMessageDecoder
ByteToMessageDecoder API
ToIntegerDecoder
public class ToIntegerDecoder extends ByteToMessageDecoder { // 扩展ByteToMessageDecoder 类,以将字节解码为特定的格式
    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in,List<Object> out) throws Exception {
        if (in.readableBytes() >= 4) {
        out.add(in.readInt());
        }
    }
}

注::一旦消息被编码或者解码,它就会被ReferenceCountUtil.release(message)调用自动释放。如果你需要保留引用以便稍后使用,那么你可以调用ReferenceCountUtil.retain(message)方法.

  • 抽象类ReplayingDecoder
    ReplayingDecoder扩展了ByteToMessageDecoder类不必调用readableBytes()方法。它通过使用一个自定义的ByteBuf实现,ReplayingDecoderByteBuf,包装传入的ByteBuf实现了这一点,其将在内部执行该调用.
public class ToIntegerDecoder2 extends ReplayingDecoder<Void> { // 扩展Replaying-Decoder<Void>以将字节解码为消息
    @Override // 传入的ByteBuf 是ReplayingDecoderByteBuf
    public void decode(ChannelHandlerContext ctx, ByteBuf in,List<Object> out) throws Exception { 
        out.add(in.readInt());
    }
}

这里有一个简单的准则:如果使用ByteToMessageDecoder 不会引入太多的复杂性,那么请使用它;否则,请使用ReplayingDecoder。

  • 抽象类MessageToMessageDecoder
    定义IntegerToStringDecoder
IntegerToStringDecoder
public class IntegerToStringDecoder extends MessageToMessageDecoder<Integer> {
    @Override
    public void decode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
        out.add(String.valueOf(msg));
    }
}
  • TooLongFrameException 类
public class SafeByteToMessageDecoder extends ByteToMessageDecoder {
    private static final int MAX_FRAME_SIZE = 1024;
    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in,
        List<Object> out) throws Exception {
        int readable = in.readableBytes();
        if (readable > MAX_FRAME_SIZE) { // 检查缓冲区中是否有超过MAX_FRAME_SIZE个字节
            in.skipBytes(readable); // 跳过所有的可读字节,抛出TooLongFrameException 并通知ChannelHandler
            throw new TooLongFrameException("Frame too big!");
        }
        // do something
        ...
    }
}

以上为解码器的常规用例.

编码器

两种作用:
1.将消息编码为字节;
2.将消息编码为消息.

  • 抽象类MessageToByteEncoder
MessageToByteEncoder API
public class ShortToByteEncoder extends MessageToByteEncoder<Short> {
    @Override
    public void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out)throws Exception {
        out.writeShort(msg);
    }
}

Netty 提供了一些专门化的MessageToByteEncoder,你可以基于它们实现自己的编码器。WebSocket08FrameEncoder 类提供了一个很好的实例。你可以在io.netty.handler.codec.http.websocketx 包中找到它。

ShortToByteEncoder
  • 抽象类MessageToMessageEncoder
IntegerToStringEncoder
public class IntegerToStringEncoder extends MessageToMessageEncoder<Integer> {
    @Override
    public void encode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
        out.add(String.valueOf(msg));
    }
}
抽象的编解码器类
  • 抽象类ByteToMessageCodec
    ByteToMessageCodec 将为我们处理好这一切,因为它结合了ByteToMessageDecoder 以及它的逆向——MessageToByteEncoder
ByteToMessageCodec API
  • 抽象类MessageToMessageCodec
    public abstract class MessageToMessageCodec<INBOUND_IN,OUTBOUND_IN>
MessageToMessageCodec 的方法

decode() 方法是将INBOUND_IN 类型的消息转换为OUTBOUND_IN 类型的消息, 而encode()方法则进行它的逆向操作。将INBOUND_IN类型的消息看作是通过网络发送的类型,而将OUTBOUND_IN类型的消息看作是应用程序所处理的类型,将可能有所裨益.

package com.hehe.netty.server;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.websocketx.*;

import java.util.List;

/**
 * @author helong
 * @date 2019/1/23 18:21
 * @description
 */
public class WebSocketConvertHandler extends MessageToMessageCodec<WebSocketFrame, WebSocketConvertHandler.MyWebSocketFrame> {
    @Override // 将MyWebSocketFrame 编码为指定的WebSocketFrame 子类型
    protected void encode(ChannelHandlerContext ctx, WebSocketConvertHandler.MyWebSocketFrame msg, List<Object> out) throws Exception {
        ByteBuf payload = msg.getData().duplicate().retain();
        switch (msg.getType()) { // 实例化一个指定子类型的WebSocketFrame
            case BINARY:
                out.add(new BinaryWebSocketFrame(payload));
                break;
            case TEXT:
                out.add(new TextWebSocketFrame(payload));
                break;
            case CLOSE:
                out.add(new CloseWebSocketFrame(true, 0, payload));
                break;
            case CONTINUATION:
                out.add(new ContinuationWebSocketFrame(payload));
                break;
            case PONG:
                out.add(new PongWebSocketFrame(payload));
                break;
            case PING:
                out.add(new PingWebSocketFrame(payload));
                break;
            default:
                throw new IllegalStateException(
                        "Unsupported websocket msg " + msg);
        }
    }
    @Override // 将WebSocketFrame 解码为MyWebSocketFrame,并设置FrameType
    protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List<Object> out) throws Exception {
        ByteBuf payload = msg.content().duplicate().retain();
        if (msg instanceof BinaryWebSocketFrame) {
            out.add(new MyWebSocketFrame(
                    MyWebSocketFrame.FrameType.BINARY, payload));
        } else
        if (msg instanceof CloseWebSocketFrame) {
            out.add(new MyWebSocketFrame (
                    MyWebSocketFrame.FrameType.CLOSE, payload));
        } else
        if (msg instanceof PingWebSocketFrame) {
            out.add(new MyWebSocketFrame (
                    MyWebSocketFrame.FrameType.PING, payload));
        } else
        if (msg instanceof PongWebSocketFrame) {
            out.add(new MyWebSocketFrame (
                    MyWebSocketFrame.FrameType.PONG, payload));
        } else
        if (msg instanceof TextWebSocketFrame) {
            out.add(new MyWebSocketFrame (
                    MyWebSocketFrame.FrameType.TEXT, payload));
        } else
        if (msg instanceof ContinuationWebSocketFrame) {
            out.add(new MyWebSocketFrame (
                    MyWebSocketFrame.FrameType.CONTINUATION, payload));
        } else
        {
            throw new IllegalStateException(
                    "Unsupported websocket msg " + msg);
        }
    }
    public static final class MyWebSocketFrame {
        public enum FrameType {
            BINARY,
            CLOSE,
            PING,
            PONG,
            TEXT,
            CONTINUATION
        }
        private final FrameType type;
        private final ByteBuf data;
        public MyWebSocketFrame(FrameType type, ByteBuf data) {
            this.type = type;
            this.data = data;
        }
        public FrameType getType() {
            return type;
        }
        public ByteBuf getData() {
            return data;
        }
    }
}
  • CombinedChannelDuplexHandler 类
    结合一个解码器和编码器可能会对可重用性造成影响。但是,有一种方法既能够避免这种惩罚,又不会牺牲将一个解码器和一个编码器作为一个单独的单元部署所带来的便利性。CombinedChannelDuplexHandler 提供了这个解决方案,其声明为:
    public class CombinedChannelDuplexHandler <I extends ChannelInboundHandler,O extends ChannelOutboundHandler>
public class ByteToCharDecoder extends ByteToMessageDecoder {
    @Override
    public void decode(ChannelHandlerContext ctx, ByteBuf in,
        List<Object> out) throws Exception {
        while (in.readableBytes() >= 2) {
            out.add(in.readChar());
        }
    }
}
public class CharToByteEncoder extends MessageToByteEncoder<Character> {
    @Override
    public void encode(ChannelHandlerContext ctx, Character msg, ByteBuf out) throws Exception {
        out.writeChar(msg);
    }
}
public class CombinedByteCharCodec extends CombinedChannelDuplexHandler<ByteToCharDecoder, CharToByteEncoder> {
    public CombinedByteCharCodec() {
        super(new ByteToCharDecoder(), new CharToByteEncoder());
    }
}

正如你所能看到的,在某些情况下,通过这种方式结合实现相对于使用编解码器类的方式来说可能更加的简单也更加的灵活。

相关文章

  • 使用Netty编写一个极简的Http服务器

    Netty是一个高性能的网络编程框架,有着简单易于使用的抽象模型。利用Netty自带的Http协议编解码器,我们可...

  • Netty学习--编解码器框架

    什么是编解码器 如果将消息看作是对于特定的应用程序具有具体含义的结构化的字节序列—它的数据。那么编码器是将消息转换...

  • DIY一些基于netty的开源框架

    几款基于netty的开源框架,有益于对netty的理解和学习! 基于netty的http server框架 htt...

  • java-netty

    netty常用API学习 netty简介 Netty是基于Java NIO的网络应用框架. Netty是一个NIO...

  • Netty学习之内置处理器以及编解码器

    Netty学习之内置处理器以及编解码器 前言 SSL/TLS SSL/TLS是目前广泛使用的加密,位于TCP之上,...

  • Netty之六编解码器和handler的调用机制

    个人专题目录 1. Netty编解码器和handler的调用机制 1.1 基本说明 netty的组件设计:Nett...

  • Netty框架学习

    最近项目引入TCP连接,Protobuf数据格式,实现在地图页面实时获取司机经纬度,使用到Netty框架,以下是学...

  • 认识netty框架,如何学习netty框架

    几年前,由于工作原因接触到了netty这个框架,从此让我对这个框架产生了强烈的好奇心,今天我没有打算讲netty框...

  • Netty源码(一):Netty中的Buffer

    最近我学习了NIO相关的知识,然后发现了Netty这个基于NIO的网络应用框架,于是就研究起Netty框架源码,来...

  • netty三 - 再学netty

    距离上个项目使用netty很久了,在学习分布式的时候,发现很多框架都是基于netty实现的,重新将netty又捡回...

网友评论

      本文标题:Netty学习--编解码器框架

      本文链接:https://www.haomeiwen.com/subject/zmqsjqtx.html