可以看到也非常的简单,介绍下我们这里用到的几个Handler
ChannelHandler 作用HttpServerCodec 对字节码根据http协议进行编码和解码,
HttpObjectAggregator 将一个 HttpMessage 和跟随它的多个 HttpContent 聚合
为单个 FullHttpRequest 或者 FullHttpResponse (取
决于它是被用来处理请求还是响应)。安装了这个之后,
ChannelPipeline 中的下一个 ChannelHandler 将只会
收到完整的 HTTP 请求或响应
HTTPRequestHandler | 处理 HttpObjectAggregator 送过来的 FullHttpRequest 请求
然后我们运行一下 ServiceMain 然后用浏览器访问一下,正常的话,如图所示。
首先,我们在刚才的 HTTPRequestHandler 的 channelRead0 方法里添加对 websocket 接口的特殊处理。修改后的代码如下
/** * @author Sean Wu */ public class HTTPRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> { protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { System.out.println(msg.uri()); // 如果后缀为 ws 的请求,则增加引用计数,将他传给下一个 ChannelInboundHandler if ("/ws".equalsIgnoreCase(msg.uri())) { ctx.fireChannelRead(msg.retain()); return; } // 之前的代码 } }然后我们要加一个处理 websocket 协议的 handler
根据WebSocket 协议,netty 定义了如下六种帧
BinaryWebSocketFrame 充满了二进制数据流的一个帧,大多是多媒体文件
TextWebSocketFrame 充满了文本的一个帧
CloseWebSocketFrame 用来关闭websocket的帧
PingWebSocketFrame 用来探活的的一个帧
PongWebSocketFrame 用来表示自己还活着的一个帧
Netty 里提供了一个叫 WebSocketServerProtocolHandler 的类,他会帮你处理 Ping,Pong,Close之类的服务状态的帧。这里我们只需要简单的用下TextWebSocketFramce就好了。
/** * @author Sean Wu */ public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) { ctx.writeAndFlush(new TextWebSocketFrame("client " + ctx.channel() + "join")); } super.userEventTriggered(ctx, evt); } protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { System.out.println(msg.text()); ctx.writeAndFlush(new TextWebSocketFrame("hello" + msg.text())); } }这里我们的例子非常的简单,可以说是网上所有 netty-websocket 的例子里最简单的了。我们只是在收到了客户端的消息之后打印了一下然后原封不动的加个 hello 返回回去。
再然后,我们要改一下我们之前的 ChannelPipeline。添加对 websocket 的支持。改完之后的代码如下
NioEventLoopGroup boss = new NioEventLoopGroup(1); NioEventLoopGroup worker = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(boss, worker) .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.DEBUG)) .childHandler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast(new HttpServerCodec()) .addLast(new HttpObjectAggregator(65536)) .addLast(new HTTPRequestHandler()) .addLast(new WebSocketServerProtocolHandler("/ws")) .addLast(new TextWebSocketFrameHandler()); } }); ChannelFuture f = b.bind(8866).sync(); f.channel().closeFuture().sync(); boss.shutdownGracefully(); worker.shutdownGracefully(); } 运行示例