stomp over websocket协议原理与实现
本文你将学习到
- websocket协议原理.
- stomp协议原理.
- websocket协议的缺点, 为什么websocket协议需要stomp协议来补充.
- spring websocket架构与实现.
- spring websocket的性能优化.
- 如何使用java编写stomp over websocket协议的client.
stomp over websocket协议原理
http协议
http协议是单工的, 只能由client发请求再由server返回请求结果, 在http协议中server是不能主动发请求到client的.
单工, 半双工, 全双工区别 参考:
http://blog.csdn.net/erwangshi/article/details/44940069
大多数情况下http协议都是适用的, 但当遇到在线聊天, 股票行情这样需要实时获取取服务端信息的应用时, client需要频繁轮询server
过程如下:
- client 建立连接
- client 问server有没有新的消息, 并根据返回结果进行处理
- client 关闭连接
- client 建立连接
- client 问server有没有新的消息, 并根据返回结果进行处理
- client 关闭连接
- …
为了拿到最新信息, client一直这样循环下去
server如果一直没有新的消息, client的大多请求都是无效的, 效率低下.
为了提高效率需要有一种协议可以让server主动发消息给client.
这样就不需要client频繁轮询, 只要server有新消息就会主动推送给client.
这种协议就是websocket协议.
websocket协议
webSocket协议是基于TCP的一种网络协议。它实现了浏览器与服务器全双工
(full-duplex)通信——允许服务器主动发送信息给客户端。
在webscoket协议中, client利用http来建立tcp连接, 建立tcp连接之后, client与server就可以基于tcp连接来愉快的进行通信了.
那么webscoket如何利用http建立连接的呢?
建立连接
client与server是利用http的一次request, response来建立连接的.
其中http request消息体如下:
GET /echo HTTP/1.1
Host:jingxu.test.com:8100
Origin:http://jingxu.test.com:8099
Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key:rVX0XFeQzA9QVXXEfjm0yw==
Sec-WebSocket-Version:13
Upgrade:websocket
其中前三个header:Get, Host, Origin都是http协议之前就有, 不多做解释, 主要解释一下后面这几个header
Sec-WebSocket-Extensions: 用于对websocket协议进行扩展. 比如websocket协议本身不支持压缩, 但可以通过Sec-WebSocket-Extensions中的permessage-deflate来协商压缩.
Sec-WebSocket-Key:client随机生成的一段key. 详情之后response中Sec-WebSocket-Accept的解释.
Sec-WebSocket-Version:协议的版本号
Upgrade:通过http的Upgrade对协议进行切换. 告诉server, 建立连接后用websocket协议.
http response消息体如下:
Connection:upgrade
Date:Mon, 04 Dec 2017 10:05:18 GMT
Sec-WebSocket-Accept:q3dUKg4lRGCqqRhGIvmE7sH8Yuc=
Sec-WebSocket-Extensions:permessage-deflate;client_max_window_bits=15
Upgrade:websocket
Connection与Date都是http协议之前就有的header, 主要解释一下后面的.
Sec-WebSocket-Accept:对应于request中的Sec-WebSocket-Key.
server会根据request中的Sec-WebSocket-Key的值来生成response中的Sec-WebSocket-Accept的值.
具体的算法是根据Sec-WebSocket-Key与协议中已定义的一个guid “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”进行拼接
再对结果进行sha1, 再对sha1的结果进行base64, 最后得到Sec-WebSocket-Accept的值.
client通过验证server返回的Sec-WebSocket-Accept的值, 来确定两件事情:
- server理解websocket协议.
如果server不理解, 那么server不会返回正确的Sec-WebSocket-Accept.
如果server没有返回正确的Sec-WebSocket-Accept, 那么建立websocket连接失败. - server返回的response是对于client的此次reuqest的响应而不是之前的缓存.
主要是防止有些缓存服务器返回缓存的response.
发送数据
现在websocket连接已经建立, 由于websocket没有规范payload的格式, 所以应用需要自己去定义payload的格式.
websocket的payload可以是文本也可以是二进制.
应用一般会选择用文本.
这个文本是什么格式websocket协议本身并没有规定, 由应用自己来定.
比如我要请求发送消息这个接口, 那么我的payload可以写成:
/send | params=我是消息
这里我自己定义了一个格式, 中坚线之前的是要调用的地址, 中竖线之后是参数.
由于格式是自己定义的, 所以在服务端我也需要自己写代码来解析这个格式.
把/send
路由到相应的处理方法.
那有没有一种统一的协议呢? 统一的标准呢?
因为这样就会有相应的已经实现的库来解析路由, 而不用自己去写, 自己去定义格式.
这个统一的协议就是stomp协议.
stomp协议
stomp是一个用于client之间进行异步消息传输的简单文本协议, 全称是Simple Text Oriented Messaging Protocol.
对于stomp协议来说, client分为消费者client与生产者client两种. server是指broker, 也就是消息队列的管理者.
stomp协议并不是为websocket设计的, 它是属于消息队列的一种协议, 和amqp, jms平级.
只不过由于它的简单性恰巧可以用于定义websocket的消息体格式.
stomp协议很多mq都已支持, 比如rabbitmq, activemq. 很多语言也都有stomp协议的解析client库.
可以这么理解, websocket结合stomp相当于一个面向公网对用户比较友好的一种消息队列.
stomp协议中的client分为两角色:
- 生产者: 通过
SEND
命令给某个目的地址(destination)发送消息. - 消费者: 通过
SUBSCRIBE
命令订阅某个目的地址(destination), 当生产者发送消息到目的地址后, 订阅此目的地址的消费者会即时收到消息.
stomp协议的结构与http结构相似, 结构如下:
COMMAND
header1:value1
header2:value2
Body^@
其中^@代表null结尾.
与http相似有三部分组成: 命令, header, 消息体.
命令与header使用utf-8格式, body可以是二进制也可以是文本.
命令有SEND, SUBSCRIBE, MESSAGE, CONNECT, CONNECTED
等.
header类似http有content-length, content-type等.
消息体类似http可以是二进制也可以是文本.
下面例举一些主要命令
建立连接
和http, websocket类似, 首先要确认双方都懂stomp这个协议, 通过建立连接来确认.
由于我们已经建立了webscoket连接, 接下来我只需要在webscoket连接的基础上建立stomp连接.
将以下内容写到websocket的payload中, 来发送建立sto