Netty 框架学习 —— 编解码器框架 (3)

任何的请求/响应协议都可以作为使用 ByteToMessageCodec 的理想选择。例如,在某个 SMTP 的实现中,编解码器将读取传入字节,并将它们解码为一个自定义的消息类型,如 SmtpRequest。而在接收端,当一个响应被创建时,将会产生一个 SmtpResponse,其将被编码回字节以便进行传输

Netty 框架学习 —— 编解码器框架

2. 抽象类 MessageToMessageCodec

通过使用 MessageToMessageCodec,我们可以在一个单个的类中实现该转换的往返过程。MessageToMessageCodec 是一个参数化的类,定义如下:

public abstract class MessageToMessageCodec<INBOUND_IN,OUTBOUND_IN>

Netty 框架学习 —— 编解码器框架

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

WebSocket 协议

下面关于 MessageToMessageCodec 的示例引用了一个新出的 WebSocket 协议,这个协议能实现 Web 浏览器和服务器之间的全双向通信

我们的 WebSocketConvertHandler 在参数化 MessageToMessageCodec 时将使用 INBOUND_IN 类型的 WebSocketFrame,以及 OUTBOUND_IN 类型的 MyWebSocketFrame,后者是 WebSocketConvertHandler 本身的一个静态嵌套类

public class WebSocketConvertHandler extends MessageToMessageCodec<WebSocketFrame, WebSocketConvertHandler.MyWebSocketFrame> { @Override protected void encode(ChannelHandlerContext ctx, MyWebSocketFrame msg, List<Object> out) throws Exception { // 实例化一个指定子类型的 WebSocketFrame ByteBuf payload = msg.getData().duplicate().retain(); switch (msg.getType()) { 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); } } // 将 WebSocketFrame 解码为 MyWebSocketFrame,并设置 FrameType @Override protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List<Object> out) throws Exception { ByteBuf paload = msg.content().duplicate().retain(); if (msg instanceof BinaryWebSocketFrame) { out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.BINARY, paload)); } else if (msg instanceof CloseWebSocketFrame) { out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.CLOSE, paload)); } else if (msg instanceof PingWebSocketFrame) { out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.PING, paload)); } else if (msg instanceof PongWebSocketFrame) { out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.PONG, paload)); } else if (msg instanceof TextWebSocketFrame) { out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.TEXT, paload)); } else if (msg instanceof ContinuationWebSocketFrame) { out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.CONTINUATION, paload)); } 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; } } } 3. CombinedChannelDuplexHandler 类

正如我们前面所提到的,结合一个解码器和编码器可能会对可重用性造成影响。但是,有一 种方法既能够避免这种惩罚,又不会牺牲将一个解码器和一个编码器作为一个单独的单元部署所 带来的便利性。CombinedChannelDuplexHandler 提供了这个解决方案,其声明为:

public class CombinedChannelDuplexHandler <I extends ChannelInboundHandler, O extends ChannelOutboundHandler>

这个类充当了 ChannelInboundHandler 和 ChannelOutboundHandler(该类的类型参数 I 和 O)的容器。通过提供分别继承了解码器类和编码器类的类型,我们可以实现一个编解码器,而又不必直接扩展抽象的编解码器类

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjypx.html