Stomp协议以及debug方法

本文介绍STOMP协议的基本概念及其实现方法,包括连接建立、消息传递及断开连接等过程。并通过具体步骤演示如何利用STOMP协议实现客户端与服务器之间的消息交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. http://blog.youkuaiyun.com/zsomsom/article/details/27076249
  2. http://blog.youkuaiyun.com/yinwenjie/article/details/50698695  (一系列文章)
  3. http://www.cnblogs.com/xuelu/p/3812817.html


Stomp是一个简单的消息文本协议,它的设计核心理念就是简单与可用性,官方文档:http://stomp.github.io/

现在我们就来实践一下Stomp协议,你需要的是: 

1.一个支持stomp消息协议的messaging server(譬如activemq,rabbitmq); 
2.一个终端(譬如linux shell); 
3.一些基本命令与操作(譬如nc,telnet) 

1.建立连接 
当我们(Client端)向服务器发送一个CONNECT Frame,就向服务器发起了一个连接请求,此时服务器端返回一个CONNECTED Frame表示建立连接成功,其中头字段version表示采用的stomp协议版本(这里默认是1.0) 

 
ps: ^@符号 ctrl+@键(用来提交请求),删除之前输入的数据 ctrl+n+backspace键 

当然Client端也可指定所支持的协议版本(accept-version字段,多个版本按递增顺序排列,并用逗号分隔); 

 

服务器此时返回的CONNECTED Frame中会列出它所支持的协议版本号中最高的那个(如上图的version:1.1) 

如果服务器端不支持客户端所列举的协议版本(比如这里的2.1),那么服务器会返回一个ERROR Frame并且列举出服务器自己所支持的协议版本(如下图的version:1.0,1.1) 

 


2.消息传递 
客户端一旦与服务器端建立连接,那么就可发送下列Frame进行消息传递 

SEND
SUBSCRIBE
UNSUBSCRIBE
ACK
NACK
BEGIN
COMMIT
ABORT
DISCONNECT


SEND Frame 用来将客户端消息发送到目的地(destination),因此它必须指定一个destination头字段,另外在所有头字段之后,新起一个空行,之后就是需要发送的消息(譬如这里的 hello stomp!) 

 

此时"hello stomp!" 这条消息就被发送到了队列 my_queue中去 

现在我们再起一个客户端clinet_a,来接受这个队列(myqueue)中的消息 

 

SUBSCRIBE Frame 表示客户端希望订阅某一个目的地(destination)的消息(这里是/queue/my_queue),其中头字段id表示在一个会话连接里,唯一 标示一个订阅者(subscription),头字段destination标示该订阅者(subscription)需要订阅的目的地(这里是一个队 列,/queue/my_queue) 

紧接着,我们就接受到服务器端发送来的消息(MESSAGE Frame),其中message_id:唯一标示了这条消息(后面我们会使用这个消息id进行ack,uack操作),content-length: 标示消息体的长度,在所有这些头后面,新起一个空行就是消息内容(如这里的hello stomp!) 

如此时我们希望订阅另一个destination,该如何办呢?,是不是再发送一个SUBSCRIBE Frame就好了? 

 

结果发现服务器端返回了ERROR Frame 告诉我们SUBSCRIBE失败,原来同一个subscription id只能订阅一个destination,要想订阅令一个destination,必须先发送UNSUBSCRIBE Frame,然后再SUBSCRIBE 到新的目的地 

 

UNSCUBSCRIBE Frame中的id标示需要取消订阅的subscription,然后我们在订阅到新的destination(这里是/queue/other_queue),可以发现订阅成功,服务器没有再发送ERROR Frame 

至此,我们就模拟出了一个PTP(point-to-point)消息模型,下面我们也模拟下另外一个pub/sub消息模型: 

准备工作,新起两个连接订阅到/topic/my_topic上,如下图: 
clinet_a 
 

client b 
 

Send端发送广播消息: 
 

我们去检查下两个消息接收客户端,果然发现收到了这条广播消息^_^ 
client a 
 

client b 
 

默认情况下,只要服务器端发送消息,就认为客户端接收成功(即ack模式为auto),若我们需要更严格的消息保证,则必须采用client模式,即由客户端确认消息的接受 

服务器发送了一个消息到/queue/ackqueue 

 

此时我们的客户端client_a确实接受到了该消息 

 

虽然该消息已经发送到客户端,但是由于该消息没有确认(ack),则该消息还保存在队列/queue/ackqueue中(直到客户端确认才删除),我们可以通过rabbitmq提供的命令来查看(sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged): 

 

若客户端在确认消息前与客户端断开连接,那么服务器可能(根据不同server的设计而不同)会选择将该消息发送给另一个subscription(这里是client_b) 

 

可以看出rabbit是选择将它发送给另一个subscription, 我们在使用命令查ack_queue队列中是否还有未确认的消息 

 

结果发现没有了 ^_^ 

若是客户端希望确认一个消息,该如何做呢?,只要发送一个ACK Frame即可! 
在ACK Frame中,subscription标示是谁确认消息,message-id标示是确认哪条消息(即MESSAGE Frame中携带的message-id) 

 

另外我在rabbitmq的测试结果发现,ack具有累积效应,譬如接收了10条消息,如果你ack了第8条消息,那么1-7条消息都会被ack,只有9-10两条消息还保持未ack状态 

除了有ACK Frame,还有NACK Frame,它表示客户端未成功接收某条消息,这时候服务器可以选择重发或者丢弃(对于rabbitmq,我的测试结果是选择重发) 


3.断开连接 
说完了连接的建立,消息的发送与接收,现在我们来看看客户端如何与服务器断开连接的,更重要的是如何安全的断开连接 

 

通过发送DISCONNNECT Frame表示向服务器发送一个断开连接请求,其中receipt表示服务器收到请求后请告知客户端,并返回一个相同的receipt-id


### UniApp 中使用 Stomp 和 WebSocket 实现消息通信 在 UniApp 开发环境中,要实现基于 Stomp 协议的 WebSocket 消息通信,可以按照以下方式进行设计和开发。以下是详细的说明和技术要点: --- #### 1. **安装必要的库** 为了简化开发流程,推荐使用社区维护良好的第三方库 `stompjs` 和 `sockjs-client` 来处理 Stomp 和 WebSocket 的交互。 ```bash npm install @stomp/stompjs sockjs-client --save ``` 这些库能够帮助开发者快速构建与后端服务器之间的实时通信通道[^2]。 --- #### 2. **初始化 WebSocket 和 Stomp 客户端** 在 UniApp 中,可以通过如下代码片段完成 Stomp 客户端的初始化工作: ```javascript import { Client } from '@stomp/stompjs'; import SockJS from 'sockjs-client'; // 配置 SockJS URL 和其他参数 const socket = new SockJS('http://your-server-url/socket-endpoint'); // 替换为实际的服务地址 const stompClient = new Client({ webSocketFactory: () => socket, debug: (str) => console.log(str), // 调试日志输出 reconnectDelay: 5000, // 自动重连时间间隔(毫秒) heartbeatIncoming: 4000, // 心跳检测配置 heartbeatOutgoing: 4000, }); // 连接到服务器 stompClient.activate(); ``` 上述代码实现了对 Stomp 客户端的基础设置,并启用了自动重连功能以增强稳定性[^3]。 --- #### 3. **订阅主题并接收消息** 通过 Stomp 订阅特定的主题路径,可以从服务器获取广播或定向的消息数据: ```javascript stompClient.onConnect = (frame) => { console.log('Connected:', frame); // 订阅某个主题 stompClient.subscribe('/topic/messages', (message) => { const parsedMessage = JSON.parse(message.body); console.log('Received message:', parsedMessage); // 将消息更新至页面或其他组件中 uni.$emit('new-message', parsedMessage); // 使用事件总线通知全局状态变化 }); // 发送测试消息给服务器 const testPayload = JSON.stringify({ content: 'Hello Server!' }); stompClient.send('/app/send/message', {}, testPayload); }; stompClient.onStompError = (frame) => { console.error('STOMP Error:', frame); }; ``` 这里展示了如何监听 `/topic/messages` 主题下的新消息到达事件,并将其转发到应用内的其他模块进行进一步处理[^4]。 --- #### 4. **断开连接** 当用户离开当前会话或者切换页面时,应主动关闭 WebSocket 连接以免浪费资源: ```javascript onUnload(() => { if (stompClient && stompClient.connected) { stompClient.deactivate().then(() => { console.log('Disconnected successfully.'); }).catch((err) => { console.warn('Failed to disconnect cleanly.', err); }); } }); ``` 此部分逻辑应在生命周期钩子函数如 `onUnload()` 或者类似的销毁阶段执行[^5]。 --- #### 5. **兼容性和性能优化建议** - **跨平台适配**:由于 UniApp 支持多个终端环境,在 iOS 和 Android 设备上可能存在细微差异,请务必充分测试各场景下表现一致性。 - **错误恢复机制**:除了简单的重新连接外,还应该加入超时判断以及提示用户体验友好型反馈信息。 - **减少无意义流量传输**:合理规划哪些内容需要即时同步,避免不必要的频繁轮询增加负担[^6]。 --- ### 示例总结 下面是一个完整的示例结构用于展示整个过程: ```javascript <template> <view class="container"> <!-- 页面布局 --> </view> </template> <script> export default { data() { return {}; }, methods: {}, onLoad() { this.initWebSocket(); }, onUnload() { this.closeWebSocket(); }, initWebSocket() { import('@stomp/stompjs').then(({ Client }) => { import('sockjs-client').then((SockJS) => { const socket = new SockJS('http://your-server-url/socket-endpoint'); const stompClient = new Client({ webSocketFactory: () => socket, debug: (str) => console.log(str), reconnectDelay: 5000, }); stompClient.onConnect = (frame) => { stompClient.subscribe('/topic/messages', (msg) => { console.log(JSON.parse(msg.body)); }); }; stompClient.activate(); }); }); }, closeWebSocket() { // 关闭逻辑同前文描述一致... }, }; </script> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值