基于Spring的WebSocket通讯(一)
首先让我们了解一下几个概念:
一、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...