stomp over websocket协议原理与实现

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

  • 18
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,下面是一个简单的示例代码,演示了如何在Spring Boot应用程序中使用STOMPWebSocket实现简单的消息传递。 首先,需要添加以下依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator-core</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>sockjs-client</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>stomp-websocket</artifactId> <version>2.3.3</version> </dependency> ``` 然后,在Spring Boot应用程序的主类上添加`@EnableWebSocketMessageBroker`注释,以启用WebSocket消息代理: ```java @SpringBootApplication @EnableWebSocketMessageBroker public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 接下来,创建一个WebSocket配置类,用于配置STOMP消息代理: ```java @Configuration public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/chat").withSockJS(); } } ``` 这里配置了一个简单的消息代理,用于处理来自`/app`前缀的应用程序消息和来自`/topic`前缀的广播消息。同时,配置了一个STOMP端点,允许使用SockJS协议进行WebSocket通信。 接下来,在控制器类中添加以下代码,处理来自客户端的消息: ```java @Controller public class ChatController { @MessageMapping("/chat") @SendTo("/topic/messages") public ChatMessage sendMessage(ChatMessage message) { return new ChatMessage(message.getFrom(), message.getText()); } } ``` 这里定义了一个处理`/chat`端点的方法,当接收到客户端发送的消息时,会将消息转发到`/topic/messages`频道上。`ChatMessage`是一个简单的POJO类,用于表示聊天消息。 最后,在前端页面中添加以下代码,用于与WebSocket服务器建立连接和发送消息: ```javascript var stompClient = null; function connect() { var socket = new SockJS('/chat'); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { console.log('Connected: ' + frame); stompClient.subscribe('/topic/messages', function (chatMessage) { showMessage(JSON.parse(chatMessage.body)); }); }); } function sendMessage() { var from = document.getElementById('from').value; var text = document.getElementById('text').value; stompClient.send("/app/chat", {}, JSON.stringify({'from': from, 'text': text})); } function showMessage(chatMessage) { var messageArea = document.getElementById('messageArea'); messageArea.innerHTML += chatMessage.from + ': ' + chatMessage.text + '\n'; } ``` 这里使用SockJS和STOMP.js客户端库来与WebSocket服务器建立连接和发送消息。`connect()`方法用于建立连接,`sendMessage()`方法用于发送消息,`showMessage()`方法用于显示接收到的消息。 以上就是一个简单的示例,演示了如何在Spring Boot应用程序中使用STOMPWebSocket实现简单的消息传递。希望能帮到你。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值