基于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...

相关推荐