WebSocket 协议是一种在单个 TCP 连接上进行全双工通信的协议,在建立连接完成握手阶段后,服务端也可以主动推送数据给客户端,使得 Web 浏览器和服务器之间的交互性更强大。
目前 WebSocket 协议应用非常广泛,大部分浏览器均已支持 WebSocket,不仅仅在 Web 应用中,其他很多类型应用(例如游戏)也经常用到 WebSocket 协议。
WebSocket 分为握手阶段( handshake )和数据传输阶段( data transfer )。
在客户端和服务器建立 WebSocket 连接之前,客户端首先要发送一个 HTTP 协议的握手请求:
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。服务器进行如下响应完成握手:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
完成握手后,接下来就是双向的数据传输的过程。
数据传输阶段传输的内容以帧( 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 协议本身的细节。
在 WebSocketServerProtocolHandler.java
216 行代码中,会在 pipeline 中添加一个 WebSocketServerProtocolHandshakeHandler
,用于处理握手阶段。具体代码位置:
https://github.com/netty/nett...
WebSocketServerProtocolHandshakeHandler
处理握手请求并响应,同时它会将自身从 pipeline 中移除,因为握手在建立 TCP 连接后仅需要处理一次。具体代码位置:
https://github.com/netty/nett...
1.我给不了你世界上最好的一切,可是我一定会把我最好的一切都给你。 2.遇到你...
在table中设置min-width和max-width属性 table trtd1/tdtd2/td/tr/tabletable{mi...
作用:数据的展示,表格应用场景. table表格 tr行 td单元格 格式: table captio...
关于元素的一些属性 在前端的日常开发中,我们经常无可避免的需要获取或者监听一...
效果 html body div class=content h3CSS3 Loading animations/h3 div class=loa...
1.对你说晚安的人很多,可只有一个人说的晚安听起来最特别。 2.女人永远不会明...
随着3G的普及,越来越多的人使用手机上网。移动设备正超过桌面设备,成为访问互...
[TOC] 简单又好用的高效工具 嗨,大家好,我是小魔童哪吒,今天给大家整理了多个...
Dreamweaver设计网页的时候,想要实现一个网页内含有两个或多个页面,该怎么实现...
前言 刚参加工作时被面试官一连串居中问题虐的体无完肤得场景历历在目。你是如何...