首先让我们了解一下几个概念:
一、WebSocket是一种全双工通讯,它是一种底层协议,其特点包括
建立在 TCP 协议之上,服务器端的实现比较容易。
与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
数据格式比较轻量,性能开销小,通信高效。
可以发送文本,也可以发送二进制数据。
没有同源限制,客户端可以与任意服务器通信。
协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
二、SockJS是WebSocket的备选方案,也是底层协议。SockJS 会优先选择 WebSocket 协议,但是如果 WebSocket协议不可用的话,他就会从如下 方案中挑选最优可行方案:
XHR streaming
XDR streaming
iFrame event source
iFrame HTML file
XHR polling
XDR polling
iFrame XHR polling
JSONP polling
三、STOMP(面向消息的简单文本协议)是基于 WebSocket(SockJS) 的上层协议,让我们这样理解STOMP与WebSocket的关系:
假设 HTTP 协议 并不存在,只能使用 TCP 套接字来 编写 web 应用,不过幸好,我们有 HTTP协议,它解决了 web 浏览器发起请求以及 web 服务器响应请求的细节;
直接使用 WebSocket(SockJS) 就很类似于使用 TCP 套接字来编写 web 应用;因为没有高层协议,因此就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;
同 HTTP 在 TCP 套接字上添加 请求-响应 模型层一样,STOMP 在 WebSocket 之上提供了一个基于 帧的线路格式层,用来定义消息语义;
上代码
Spring websocket提供了spring-messaging模块,在spring继承了Message, MessageChannel, MessageHandler等在服务器中,能处理这种消息机制的功能,spring websocket还提供了基于注解的消息处理支持。
一、pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 消息处理方面,现在不是http,无法使用spring的HttpMessageConverter, 如果传输json数据的话,需要添加jackson,不然不会连接成功 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.1-1</version>
</dependency>
二、配置WebSocketConfig
@Configuration
@EnableWebSocketMessageBroker //enables WebSocket message handling, backed by a message broker.
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
static final String MESSAGE_BROKER = "/topic";
static final String DESTINATION_PREFIX = "/app";
// 定义消息代理,通俗一点讲就是设置消息连接请求的各种规范信息。
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 客户端订阅地址的前缀信息,可以为多个,用逗号分隔
config.enableSimpleBroker(MESSAGE_BROKER);
// 服务端接收地址的前缀,意思就是说客户端给服务端发消息的地址的前缀
config.setApplicationDestinationPrefixes(DESTINATION_PREFIX);
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// registers the "/gs-guide-websocket" endpoint, enabling SockJS fallback options
// so that alternate transports may be used if WebSocket is not available.
// The SockJS client will attempt to connect to "/gs-guide-websocket" and use the
// best transport available (websocket, xhr-streaming, xhr-polling, etc).
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
}
三、Server消息处理
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws InterruptedException {
Thread.sleep(1000); //simulated delay
return new Greeting("Hello, " + message.getName());
}
四、Client消息接收发送
var socket = new SockJS('/gs-guide-websocket');//注意/gs-guide-websocket就是在server这边register的endpoint
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
// '/topic'就是Server设定传消息的prefix
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
// 这里用客户端发送消息给服务端,也可以是其他地方用stomp发送消息给服务端
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
可运行代码在这: https://github.com/even713/Sp…
参考资料: https://www.zhihu.com/questio…
https://blog.csdn.net/pacoson…