导语
本篇文章以websocket的原理和落地为核心,来叙述websocket的使用,以及相关应用场景。
websocket概述
http与websocket
如我们所了解,http连接为一次请求一次响应(request->response),必须为同步调用方式。
而websocket为一次连接以后,会建立tcp连接,后续客户端与服务器交互为全双工方式的交互方式,客户端可以发送消息到服务端,服务端也可将消息发送给客户端。
此图来源于Websocket协议的学习、调研和实现,如有侵权问题,告知后,删除。
根据上图,我们大致可以了解到http与websocket之间的区别和不同。
为什么要使用websocket
那么了解http与websocket之间的不同以后,我们为什么要使用websocket呢? 他的应用场景是什么呢?
我找到了一个比较符合websocket使用场景的描述
“The best fit for WebSocket is in web applications where the client and server need to exchange events at high frequency and with low latency.”
翻译: 在客户端与服务器端交互的web应用中,websocket最适合在高频率低延迟的场景下,进行事件的交换和处理
了解以上知识后,我举出几个比较常见的场景:
- 游戏中的数据传输
- 股票K线图数据
- 客服系统
根据如上所述,各个系统都来使用websocket不是更好吗?
其实并不是,websocket建立连接之后,后边交互都由tcp协议进行交互,故开发的复杂度会较高。当然websocket通讯,本身要考虑的事情要比HTTP协议的通讯考虑的更多.
所以如果不是有特殊要求(即 应用不是”高频率低延迟”的要求),需要优先考虑HTTP协议是否可以满足。
比如新闻系统,新闻的数据晚上10分钟-30分钟,是可以接受的,那么就可以采用HTTP的方式进行轮询(polling)操作调用REST接口。
当然有时我们建立了websocket通讯,并且希望通过HTTP提供的REST接口推送给某客户端,此时需要考虑REST接口接受数据传送给websocket中,进行广播式的通讯方式。
至此,我已经讲述了三种交互方式的使用场景:
- websocket独立使用场景
- HTTP独立使用场景
- HTTP中转websocket使用场景
相关技术概念
websocket
websocket为一次HTTP握手后,后续通讯为tcp协议的通讯方式。
当然,和HTTP一样,websocket也有一些约定的通讯方式,http通讯方式为http开头的方式,e.g. http://xxx.com/path ,websocket通讯方式则为ws开头的方式,e.g. ws://xxx.com/path
SSL:
- HTTP: https://xxx.com/path
- WEBSOCKET: wss://xxx.com/path
此图来源于WebSocket 教程,如有侵权问题,告知后,删除。
SockJS
正如我们所知,websocket协议虽然已经被制定,当时还有很多版本的浏览器或浏览器厂商还没有支持的很好。
所以,SockJS,可以理解为是websocket的一个备选方案。
那它如何规定备选方案的呢?
它大概支持这样几个方案:
- Websockets
- Streaming
- Polling
当然,开启并使用SockJS后,它会优先选用websocket协议作为传输协议,如果浏览器不支持websocket协议,则会在其他方案中,选择一个较好的协议进行通讯。
看一下目前浏览器的支持情况:
所以,如果使用SockJS进行通讯,它将在使用上保持一致,底层由它自己去选择相应的协议。
可以认为SockJS是websocket通讯层上的上层协议。
底层对于开发者来说是透明的。
STOMP
STOMP 中文为: 面向消息的简单文本协议
websocket定义了两种传输信息类型: 文本信息 和 二进制信息 ( text and binary ).
类型虽然被确定,但是他们的传输体是没有规定的。
当然你可以自己来写传输体,来规定传输内容。(当然,这样的复杂度是很高的)
所以,需要用一种简单的文本传输类型来规定传输内容,它可以作为通讯中的文本传输协议,即交互中的高级协议来定义交互信息。
STOMP本身可以支持流类型的网络传输协议: websocket协议和tcp协议
它的格式为:
COMMAND header1:value1 header2:value2 Body^@ SUBSCRIBE id:sub-1 destination:/topic/price.stock.* ^@ SEND destination:/queue/trade content-type:application/json content-length:44 {"action":"BUY","ticker":"MMM","shares",44}^@
当然STOMP已经应用于很多消息代理中,作为一个传输协议的规定,如:RabbitMQ, ActiveMQ
我们皆可以用STOMP和这类MQ进行消息交互.
除了STOMP相关的代理外,实际上还提供了一个stomp.js,用于浏览器客户端使用STOMP消息协议传输的js库。
让我们很方便的使用stomp.js进行与STOMP协议相关的代理进行交互.
正如我们所知,如果websocket内容传输信息使用STOMP来进行交互,websocket也很好的于消息代理器进行交互(如:RabbitMQ, ActiveMQ)
这样就很好的提供了消息代理的集成方案。
总结,使用STOMP的优点如下:
- 不需要自建一套自定义的消息格式
- 现有stomp.js客户端(浏览器中使用)可以直接使用
- 能路由信息到指定消息地点
- 可以直接使用成熟的STOMP代理进行广播 如:RabbitMQ, ActiveMQ
技术落地
后端技术方案选型
websocket服务端选型:spring websocket
支持SockJS,开启SockJS后,可应对不同浏览器的通讯支持
支持STOMP传输协议,可无缝对接STOMP协议下的消息代理器(如:RabbitMQ, ActiveMQ)
前端技术方案选型
前端选型: stomp.js,sockjs.js
后端开启SOMP和SockJS支持后,前对应有对应的js库进行支持.
所以选用此两个库.
总结
上述所用技术,是这样的逻辑:
- 开启socktJS:
如果有浏览器不支持websocket协议,可以在其他两种协议中进行选择,但是对于应用层来讲,使用起来是一样的。
这是为了支持浏览器不支持websocket协议的一种备选方案 - 使用STOMP:
使用STOMP