简介

在上一篇文章中,我们使用了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种类型,分别是:

BinaryWebSocketFrame
CloseWebSocketFrame
ContinuationWebSocketFrame
PingWebSocketFrame
PongWebSocketFrame
TextWebSocketFrame

其中真正包含内容的是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. lambda表达式和查询表达式
  2. 改进网站设计的免费jQuery插件Top 7
  3. iOS学习笔记(2)--Xcode6.1创建仅xib文件无storyboard的hello world应用
  4. ngModel
  5. HDU 3371 kruscal/prim求最小生成树 Connect the Cities 大坑大坑
  6. AxWindowsMediaPlayer创建、添加播放列表(C#)
  7. opcache运行时配置参数详解
  8. bootstrap 模态框关闭状态怎么获取
  9. hdu Fibonacci
  10. javascript this的一些误解
  11. Spring MVC 文件下载时候 发现IE不支持
  12. 解决android 大图OOM的两种方法
  13. appium在android 7.0真机上运行报错command failed shell:............ps:&#39;uiautomator&quot;的解决方式
  14. Ubuntu 增加swap空间大小
  15. hdu 2036:改革春风吹满地(叉积求凸多边形面积)
  16. 织梦导航条dropdown.js的改进(2013-7-10)
  17. python--数据持久化
  18. Flask实战第61天:帖子板块过滤显示
  19. 为什么用strlcpy取代strncpy
  20. jsp、freemarker、velocity对比

热门文章

  1. 图解Win 10 应用开发之Sqlite 数据库的简单用法
  2. git新建分支及提交代码到分支
  3. Verilog实例数组
  4. REST设计风格:你写的 RESTful API 到第几层了?
  5. 恶意软件开发——shellcode执行的几种常见方式
  6. 一文彻底弄懂this关键字用法
  7. Panel添加边框颜色和边框粗细调整
  8. C++模板使用
  9. vue JS获取当前时间并格式化 ( 前端小细节,大进步 )
  10. GIS常用算法