一、什么是Websocket
根据 RFC 6455 标准,Websocket协议提供了一种标准化的方式在客户端和服务端之间通过TCP连接建立全双工、双向通信渠道。它是一种不同于HTTP的TCP协议,但是被设计为在HTTP基础上运行。
Websocket交互始于HTTP请求,该请求会通过HTTP Upgrade请求头去升级请求,进而切换到Websocket协议。请求报文如下:
GET /spring-websocket-portfolio/portfolio HTTP/1.1 Host: localhost:8080 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg== Sec-WebSocket-Protocol: v10.stomp, v11.stomp Sec-WebSocket-Version: 13 Origin: http://localhost:8080
我们可以看到在该请求报文中有两个特殊的请求头,一个是Upgrade请求头,代表升级为websocket协议。还有一个是Connection请求头,代表升级连接。
正常的HTTP响应报文如果正常返回,响应码是200,请求升级为websocket协议的响应报文如下:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0= Sec-WebSocket-Protocol: v10.stomp
我们可以看到该响应报文中状态行返回的响应码是101,后面还附带了Switching Protocols切换协议关键字。
在成功握手后,底层HTTP升级请求TCP套接字会在客户端和服务端之间保持开放,从而继续发送和接收消息。
备注:关于Websockets如何工作的完整文档可以参考 RFC 6455。
二、WebSocket部分header介绍
我们可以看到请求和响应报文中有一些特殊的websocket头部信息,这里简单的介绍一下:
- Sec-WebSocket-Key:用于客户端与服务端初次握手唯一标识,Base64编码字符串。
- Sec-WebSocket-Accept:初次握手服务端返回的唯一标识,也是Base64编码字符串,用来证明来自客户端的握手请求已经收到了,该响应头的值为:SHA-1(“
Sec-WebSocket-Key
” + “GUID
”),然后再经过Base64编码。
备注:这里的GUID为固定值 258EAFA5-E914-47DA-95CA-C5AB0DC85B11。
Sec-WebSocket-Protocol:WebSocket子协议,比如可以是STOMP协议。
Sec-WebSocket-Version:WebSocket协议版本号,值必须为13。
三、HTTP VS WebSocket
虽然WebSocket被设计成和HTTP协议兼容,但是两种协议有不同的架构和应用编程模型。
在HTTP和REST中,应用被模型化为许多URL,客户端和应用交互需要访问这些URL,服务端对请求进行路由并交给合适的处理器,处理器会基于HTTP URL、方法和头部进行处理。
WebSocket和HTTP相反,通常只有一个URL用于初始链接,后面所有应用消息都会在相同的TCP连接上传输,这是一种完全不同的异步、事件驱动的消息。
WebSocket也是一种低级的传输协议,不像HTTP,它并没有规定消息内容的语义,也就意味着客户端和服务端之间如果没有对消息语义达成一致,是没办法路由和处理消息的。
WebSocket客户端和服务端之间可以协商使用更高级消息协议,比如STOMP,可以通过HTTP握手请求的请求头Sec-WebSocket-Protocol指定。
四、什么时候使用WebSockets
WebSockets可以让Web页面动态化和可交互,然而,在很多场景下,AJAX和HTTP Streaming或者长轮询也能提供简单、有效的解决方案。
例如,新闻、邮件和社会实事需要动态更新,每几分钟更新一次就好。而协作类、游戏和金融类APP需要更加的实时。
延时也不是决定性因素,如果消息体量比较小,HTTP Streaming或者长轮询也能解决,而像低延时、高频次和大消息体量的场景,WebSocket更适合。
五、关于SockJS和STOMP
SockJS 和 STOMP 都是用于 Web 应用程序与消息代理进行通信的技术,但它们解决的问题不同。
SockJS 是一个 JavaScript 库,它提供了一种在 Web 浏览器和 Web 服务器之间建立 WebSocket 连接的跨浏览器解决方案。
SockJS 旨在解决 WebSocket 不受支持或无法使用的情况下,使用轮询和其他技术建立实时双向通信的问题。SockJS 库支持多种传输方式,包括 WebSocket、XHR 流、XHR 短轮询等,从而保证了最大的兼容性和可靠性。
STOMP(Simple Text Oriented Messaging Protocol)是一种基于文本的简单消息协议,它提供了一种可互操作性的机制,用于跨语言和平台之间的实时消息传递。
STOMP 协议定义了一组命令和消息格式,用于在客户端和服务器之间进行消息传递,它与特定的消息代理无关,因此可以使用 STOMP 协议与多个消息代理进行通信。STOMP 支持订阅/发布模式和点对点模式,可以用于实现诸如聊天室、通知系统和实时数据更新等应用程序。
通常情况下,使用 SockJS和 STOMP结合使用可以获得最佳的性能和可靠性。
SockJS 提供了一种建立 WebSocket 连接的可靠跨浏览器解决方案,而 STOMP 提供了一种在 WebSocket 连接上实现实时消息传递的标准化协议。
在使用 SockJS 和 STOMP 的组合时,可以使用 SockJS 建立 WebSocket 连接,然后使用 STOMP 协议在 WebSocket 连接上进行消息传递,从而获得最佳的性能和可靠性。