學(xué)校網(wǎng)站建設(shè)的優(yōu)勢和不足成人用品推廣網(wǎng)頁
STOMP(Simple Text Oriented Messaging Protocol,簡單面向文本的消息傳遞協(xié)議)是一種輕量級、基于文本的協(xié)議,旨在為消息代理(消息隊列)和客戶端之間的通信(websocket)提供一種簡單的接口。它通常運行在TCP或WebSocket之上,并廣泛用于實現(xiàn)發(fā)布/訂閱、點對點消息傳遞等模式。
STOMP提供了一種簡單的機(jī)制來發(fā)送和接收消息,適用于各種消息中間件系統(tǒng),如ActiveMQ、RabbitMQ和Apache Kafka等。
特點:
- 基于文本的協(xié)議,簡單易用,適合快速開發(fā)。
- 支持多種消息傳遞模式(如發(fā)布/訂閱、點對點)。
- 支持事務(wù)和消息確認(rèn)機(jī)制。
- 輕量級,適用于資源受限的環(huán)境(寬帶低等)。
- 支持多種消息代理(如RabbitMQ、ActiveMQ)。
- 支持客戶端之間的通信(如:websocket)
適用場景:
- 實時通信應(yīng)用(如聊天系統(tǒng)、社交網(wǎng)絡(luò))。
- 微服務(wù)之間的異步通信。
- IoT設(shè)備之間的輕量級通信。
1、STOMP基本概念
(1)、目的地(Destination)
目的地是消息發(fā)送或接收的目標(biāo)地址。
常見的目的地類型包括:
- 隊列(Queue):點對點消息傳遞模式,每條消息只會被一個消費者處理。
- 主題(Topic):發(fā)布/訂閱模式,每條消息會被所有訂閱者處理。
(2)、命令(Commands)
STOMP定義了若干命令,用于控制消息的發(fā)送、接收和管理。
常見的命令包括:
- CONNECT:建立連接。
- SEND:發(fā)送消息到指定的目的地。
- SUBSCRIBE:訂閱某個目的地,接收該目的地的消息。
- UNSUBSCRIBE:取消訂閱某個目的地。
- ACK:確認(rèn)消息已被成功處理。
- NACK:拒絕或無法處理消息。
- DISCONNECT:斷開連接。
(3)、頭信息(Headers)
頭信息是伴隨每個命令的鍵值對,用于傳遞額外的元數(shù)據(jù)。
常見的頭信息包括:
- destination:消息的目的地。
- id:訂閱的唯一標(biāo)識符。
- receipt:請求服務(wù)器返回一個收據(jù),確認(rèn)命令已執(zhí)行。
(4)、消息體(Body)
消息體包含實際的消息內(nèi)容,可以是任意格式的數(shù)據(jù)(如JSON、XML、純文本等)。消息體必須以空字節(jié)\u0000結(jié)束。
2、STOMP消息格式
每條STOMP消息由命令行、頭信息和消息體組成,各部分之間用換行符\n分隔,整個消息以兩個連續(xù)的換行符\n\n結(jié)束。
示例:CONNECT命令
CONNECT
accept-version:1.2
host:stomp.example.com^@
解釋:
- CONNECT:命令名稱。
- accept-version:1.2:表示支持的STOMP版本。
- host:stomp.example.com:目標(biāo)主機(jī)。
- ^@:表示消息體為空,用一個空字節(jié)(ASCII碼為0)來表示。
示例:SEND命令
SEND
destination:/queue/workHello, STOMP!
^@
解釋:
- SEND:命令名稱。
- destination:/queue/work:消息的目的地。
- Hello, STOMP!:消息的內(nèi)容。
- ^@:表示消息結(jié)束。
示例:SUBSCRIBE命令
SUBSCRIBE
id:sub-001
destination:/topic/greetings^@
解釋:
- SUBSCRIBE:命令名稱。
- id:sub-001:訂閱的唯一標(biāo)識符。
- destination:/topic/greetings:要訂閱的主題地址。
- ^@:表示消息體為空。
3、STOMP工作流程
原理示意圖:
(1)、連接
客戶端首先需要通過CONNECT命令與STOMP服務(wù)器建立連接。如果連接成功,服務(wù)器會返回一個CONNECTED響應(yīng)。
客戶端示例:
CONNECT
accept-version:1.2
host:stomp.example.com^@
服務(wù)器響應(yīng)示例:
CONNECTED
version:1.2
session:session-id-12345^@
(2)、訂閱
客戶端可以通過SUBSCRIBE命令訂閱某個目的地,接收該目的地的消息。
客戶端示例:
SUBSCRIBE
id:sub-001
destination:/topic/greetings^@
(3)、發(fā)送消息
客戶端可以通過SEND命令向某個目的地發(fā)送消息。
客戶端示例:
SEND
destination:/queue/workHello, STOMP!
^@
(4)、接收消息
當(dāng)有消息到達(dá)客戶端訂閱的目的地時,服務(wù)器會將消息推送到客戶端。
消息示例:
MESSAGE
subscription:sub-001
message-id:message-id-67890
destination:/topic/greetingsHello, World!
^@
(5)、斷開連接
客戶端可以通過DISCONNECT命令斷開與服務(wù)器的連接。
客戶端示例:
DISCONNECT^@
4、在WebSocket上使用STOMP
在WebSocket之上使用STOMP時,STOMP消息作為WebSocket數(shù)據(jù)幀的有效載荷進(jìn)行傳輸。這種方式結(jié)合了WebSocket的全雙工通信能力和STOMP的結(jié)構(gòu)化消息傳遞功能。
示例:JavaScript中使用WebSocket和STOMP
const socket = new WebSocket('ws://example.com/stomp-endpoint'); // 建立websocket連接socket.onopen = function() {// 發(fā)送CONNECT命令const connectMessage = CONNECT\naccept-version:1.2\nhost:example.com\n\n\u0000;socket.send(connectMessage);// 發(fā)送SUBSCRIBE命令const subscribeMessage = SUBSCRIBE\nid:sub-001\ndestination:/topic/greetings\n\n\u0000;socket.send(subscribeMessage);
};socket.onmessage = function(event) {console.log('Received:', event.data);// 解析收到的STOMP消息if (event.data.startsWith('MESSAGE')) {console.log('New message:', event.data.split('\n\n')[1].trim());}
};
5、代碼示例
依賴庫:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-messaging</artifactId>
</dependency>
發(fā)送消息:
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.concurrent.ExecutionException;public class StompProducer {public static void main(String[] args) throws ExecutionException, InterruptedException {// 創(chuàng)建 WebSocket 客戶端StandardWebSocketClient wsClient = new StandardWebSocketClient();SockJsClient sockJsClient = new SockJsClient(Collections.singletonList(new WebSocketTransport(wsClient)));// 創(chuàng)建STOMP客戶端WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);stompClient.setMessageConverter(new MappingJackson2MessageConverter());// 連接到STOMP代理StompSession session = stompClient.connect("ws://localhost:8080/ws", new StompSessionHandlerAdapter() {}).get();// 發(fā)送消息StompHeaders headers = new StompHeaders();headers.setDestination("/app/hello");session.send(headers, "Hello, STOMP!");System.out.println("Message sent");}
}
接收消息:
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.concurrent.ExecutionException;public class StompConsumer {public static void main(String[] args) throws ExecutionException, InterruptedException {// 創(chuàng)建WebSocket客戶端StandardWebSocketClient wsClient = new StandardWebSocketClient();SockJsClient sockJsClient = new SockJsClient(Collections.singletonList(new WebSocketTransport(wsClient)));// 創(chuàng)建STOMP客戶端WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);stompClient.setMessageConverter(new MappingJackson2MessageConverter());// 連接到STOMP代理StompSession session = stompClient.connect("ws://localhost:8080/ws", new StompSessionHandlerAdapter() {}).get();// 訂閱主題并設(shè)置回調(diào)session.subscribe("/topic/greetings", new StompFrameHandler() {@Overridepublic Type getPayloadType(StompHeaders headers) {return String.class;}@Overridepublic void handleFrame(StompHeaders headers, Object payload) {System.out.println("Received message: " + payload);}});// 保持連接Thread.sleep(Long.MAX_VALUE);}
}
6、總結(jié)
STOMP是一種簡單而強(qiáng)大的消息傳遞協(xié)議,特別適合于需要靈活消息路由的應(yīng)用場景。通過運行在WebSocket或其他傳輸協(xié)議之上。
STOMP提供了以下優(yōu)勢:
- 易用性:基于文本的協(xié)議,易于實現(xiàn)和調(diào)試。
- 靈活性:支持多種消息傳遞模式,適應(yīng)不同的應(yīng)用場景。
- 跨平臺:可以在多種編程語言和平臺上使用,具有良好的互操作性。
通過理解STOMP的基本概念、命令和工作流程,開發(fā)者可以有效地利用這一協(xié)議構(gòu)建高效的消息傳遞系統(tǒng)。
乘風(fēng)破浪!Dare to Be!!!