WebSocket 协议是一种在单个 TCP 链接上进行全双工通讯的协议,在创建链接完成握手阶段后,服务端也能够主动推送数据给客户端,使得 Web 浏览器和服务器之间的交互性更强大。html
目前 WebSocket 协议应用很是普遍,大部分浏览器均已支持 WebSocket,不单单在 Web 应用中,其余不少类型应用(例如游戏)也常常用到 WebSocket 协议。java
WebSocket 分为握手阶段( handshake )和数据传输阶段( data transfer )。git
在客户端和服务器创建 WebSocket 链接以前,客户端首先要发送一个 HTTP 协议的握手请求:github
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13
其中请求头 Connection: Upgrade
和 Upgrade: websocket
表示客户端想要升级协议为 WebSocket。服务器进行以下响应完成握手:web
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol: chat
完成握手后,接下来就是双向的数据传输的过程。segmentfault
数据传输阶段传输的内容以帧( frame )为单位,其中分为控制帧(Control Frame)和数据帧(Data Frame):浏览器
Close
、Ping
、Pong
帧,Close
用于关闭 WebSocket 链接,Ping
和 Pong
用于心跳检测Text
和 Binary
帧,分别用于传输文本和二进制数据public class WebSocketServer { public static void main(String[] args) throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); // HTTP 协议解析,用于握手阶段 pipeline.addLast(new HttpObjectAggregator(65536)); // HTTP 协议解析,用于握手阶段 pipeline.addLast(new WebSocketServerCompressionHandler()); // WebSocket 数据压缩扩展 pipeline.addLast(new WebSocketServerProtocolHandler("/", null, true)); // WebSocket 握手、控制帧处理 pipeline.addLast(new MyWebSocketServerHandler()); } }); ChannelFuture f = b.bind(8080).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } class MyWebSocketServerHandler extends SimpleChannelInboundHandler<WebSocketFrame> { @Override protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { if (frame instanceof TextWebSocketFrame) { // 此处仅处理 Text Frame String request = ((TextWebSocketFrame) frame).text(); ctx.channel().writeAndFlush(new TextWebSocketFrame("收到: " + request)); } } }
以上是 Netty 实现的一个简单的 WebSocket 的服务器。启动成功后,能够网上搜索 WebSocket 在线测试工具链接 ws://localhost:8080/ 进行测试。服务器
WebSocketServerProtocolHandler
会帮咱们处理握手、Close
、Ping
、Pong
帧等 WebSocket 协议底层,而且将 Text
和 Binary
数据帧传递给 pipeline 中下一个 handler。也就是在下一个 handler 中,咱们只须要实现业务逻辑而无需关注 WebSocket 协议自己的细节。websocket
在 WebSocketServerProtocolHandler.java
216 行代码中,会在 pipeline 中添加一个 WebSocketServerProtocolHandshakeHandler
,用于处理握手阶段。具体代码位置:
https://github.com/netty/nett...socket
WebSocketServerProtocolHandshakeHandler
处理握手请求并响应,同时它会将自身从 pipeline 中移除,由于握手在创建 TCP 链接后仅须要处理一次。具体代码位置:
https://github.com/netty/nett...