写点什么

netty 系列之: 分离 websocket 处理器

发布于: 1 小时前

简介在上一篇文章中,我们使用了 netty 构建了可以处理 websocket 协议的服务器,在这个服务器中,我们构建了特制的 handler 用来处理 HTTP 或者 websocket 请求。


在一个 handler 中处理两种不同的请求,对于某些有代码洁癖的人可能忍受不了。那么,有没有可能将普通的 HTTP 请求和 websocket 请求使用不同的 handler 来进行处理呢?答案是肯定的。


netty 的消息处理我们知道 netty 中所有的消息处理都是通过 handler 来实现的,为了方便起见,netty 提供了一个简单的消息处理类 SimpleChannelInboundHandler,大家通过继承它来重写 channelRead0 方法即可:


protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;我们再看一下 SimpleChannelInboundHandler 的定义:


public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter 可以看到 SimpleChannelInboundHandler 本身是带有泛型 I 的,而这个 I 就是我们要探讨的方向。


如果我们要使用这个 handler 来处理所有的消息,那么可以将 I 取值为 Object。


如果我们只需要处理 String 消息,那么可以这样:


   public class StringHandler extends           SimpleChannelInboundHandler<String> {
@Override protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception { System.out.println(message); } }
复制代码


同样的,如果要同时处理 HTTP 和 WebSocket 消息,只需要将 I 设置为不同的类型即可。


对于 WebSocketFrame,我们有:


public class Server2FrameHandler extends SimpleChannelInboundHandler<WebSocketFrame>对于 FullHttpRequest,我们有:


public class Server2HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest>处理 WebSocketFrame 对于 WebSocketFrame 消息,从上一节我们知道它有 6 种类型,分别是:


BinaryWebSocketFrameCloseWebSocketFrameContinuationWebSocketFramePingWebSocketFramePongWebSocketFrameTextWebSocketFrame 其中真正包含内容的是 TextWebSocketFrame 和 BinaryWebSocketFrame,这里我们对 TextWebSocketFrame 进行专门处理:


protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
if (frame instanceof TextWebSocketFrame) { // 将接收到的消息转换成为大写 String request = ((TextWebSocketFrame) frame).text(); ctx.channel().writeAndFlush(new TextWebSocketFrame(request.toUpperCase(Locale.CHINA))); } else { String message = "不支持的Frame类型: " + frame.getClass().getName(); throw new UnsupportedOperationException(message); }}
复制代码


处理 HTTP 对于 HTTP 请求中的 FullHttpRequest,我们就安装正常的 HTTP 服务请求的处理流程来就行。


这里不做过多阐述。


编码和解码器等等,我们是不是忘记了什么东西?对,那就是编码和解码器。


在上一节中,我们使用的是 WebSocketServerHandshaker 来对 websocket 消息进行编码和解码。不过其实是放在我们自定义的 hadler 代码里面的,使用起来略显不优雅。


没关系,netty 为我们提供了一个 WebSocketServerProtocolHandler 类,专门负责 websocket 的编码和解码问题。


除了处理正常的 websocket 握手之外,WebSocketServerProtocolHandler 类还为我们处理了 Close, Ping, Pong 这几种通用的消息类型。而我们只需要专注于真正的业务逻辑消息即可,十分的方便。


对于剩下的 Text 或者 Binary frame 数据,会被交由 pipline 中的下一个 handler 进行处理。


其中 Handshake 有两个状态,分别是:


HANDSHAKE_COMPLETE 和 HANDSHAKE_TIMEOUT。


而 HandshakeComplete 又包含了 requestUri,requestHeaders 和 selectedSubprotocol 这三个方面的信息。


最后,将 WebSocketServerProtocolHandler 加入到 pipeline 中,最终得到:


public void initChannel(SocketChannel ch) throws Exception {    ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(65536)); pipeline.addLast(new WebSocketServerCompressionHandler()); pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true)); pipeline.addLast(new Server2HttpHandler()); pipeline.addLast(new Server2FrameHandler());}
复制代码


总结一个分离了 HTTP 请求和 webSocket 请求的服务器就完成了。简单直观才是一个程序员追求的世界!


本文的例子可以参考:learn-netty4


本文已收录于 http://www.flydean.com/24-netty-websocket-server2/


最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!


欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 1 小时前阅读数: 9
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
netty系列之:分离websocket处理器