StringBoot: 整合Websocket

Websocket简介:

Websocket是一种在单个TCP连接上进行全双工通信的协议,已被定为W3C标准。其允许服务端主动向客户端推送数据。

WebSocket协议中,浏览器和服务器只需要完成一次握手,2者之间就可以直接创建持久性的连接,进行双向数据传输。

WebSocket使用了HTTP/1.1的协议升级特性。一个WebSocket请求首先使用非正常的HTTP、HTTPS。在一个请求头中有一个Connection:Upgrade字段,表示客户端想要对协议进行升级。还有一个Upgrade:websocket字段,表示客户端想要将请求的协议升级为WebSocket协议。

  • Connection:Upgrade
  • Upgrade:websocket

这2个字段共同告诉服务器将连接升级为Websocket全双工协议。如果服务端同意协议升级,那么握手完成后,文本消息或者2进制消息就可以同时在2个方向上进行发送,而不需要关闭和重建连接。此时的客户端和服务端的关系是对等的,可以互相向对方主动发送消息。


为什么需要Websocket:

Websocket的主要优点:

  • 使用时需要先创建连接,这使得Websocket成为一种有状态的协议。在之后的通信过程中可以省略部分状态信息。(身份认证等)
  • 连接在端口80(ws)/443(wss)上创建,与http使用的端口相同。基本上所有的防火墙都不会阻止Websocket连接。
  • 使用HTTP协议进行握手。可以自然的集成到网络浏览器和HTTP服务器中,不需要额外的成本。
  • 心跳消息(ping、pong)将被反复的发送,进而保持Websocket连接一只处于活跃的状态。
  • 当消息启动或者到达的时候,服务端和客户端都可以知道。
  • 连接关闭时将发送一个特殊的关闭消息。
  • 支持跨域,避免Ajax的限制。
  • HTTP规范要求浏览器将并发连接数限制为每个主机名2个连接,但是当使用websocket的时候,当握手完后该限制就不存在 了,此时的连接不再是http连接了。
  • 支持扩展,用户可以扩展协议,实现部分自定义的子协议。
  • 更好的2进制支持以及更好的压缩效果。

SpringBoot整合Websocket:

1.创建项目并添加依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>stomp-websocket</artifactId>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1</version>
        </dependency>

依赖说明:

spring-boot-starter-websocket: websocket的相关依赖

其余的是前端库,jar包形式管理前端库。webjar添加到项目中的前端库。SpringBoot默认添加了静态资源过滤。

2.配置Websocket:

Spring提供了基于Websocket的STOMP支持。STOMP是一个简单的可互操作的协议,常用于通过中间服务器在客户端之间进行异步消息传递。

3.定义Controller:

根据websocket的配置,可以直到,@MessageMapping("/hi")是用来接收"/app/hi"路径发送来的消息,方法对消息进行处理后,再将消息转发到@SendTo定义的路径上。而/topic/hellos的前缀是/topic,根据websocket的配置,该消息会被交给消息代理broker,由broker进行广播。

4.定义实体类:

5.编写前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>一起聊天吧!</title>
    <script src="/webjars/jquery/jquery.min.js"></script>
    <script src="/webjars/sockjs-client/sockjs.min.js"></script>
    <script src="/webjars/stomp-websocket/stomp.min.js"></script>
</head>
<body>
    <div>
        <label for="name">输入用户名:</label>
        <input type="text" id="name" placeholder="username">
    </div>

    <div>
        <button id="connect" type="button">上线</button>
        <button id="disconnect" type="button" disabled="disabled">下线</button>
    </div>

    <div id="chat" style="display:none">

    </div>

    <div>
        <label for="content">Edit your communication's content:</label>
        <input  id="content" type="text" placeholder="待发送的内容">
    </div>

    <button id="send" type="button">发送</button>
    <div id="hi">
        <div id="conversation" style="display: none">you are Chatting...</div>
    </div>

    <script>
        let stompClient = null;
        function setConnected(connected) {
            $("#connect").prop("disabled", connected);
            $("#disconnect").prop("disabled",!connected);
            if(connected){
                $("#conversation").show()
                $("#chat").show();
            }else{
                $("#conversation").hide()
                $("#chat").hide();
            }
            $("#hi").html("");
        }

        //建立一个websocket连接。用户必须先输入用户名,才能建立连接
        function connect() {
            if(!$("#name").val()){
                return;
            }
            let socket = new SockJS('/chat');
            stompClient = Stomp.over(socket);
            stompClient.connect({},function (frame) {
                setConnected(true);
                stompClient.subscribe('/topic/hellos',function (data) {//订阅服务端发送回来的消息
                    showHi(JSON.parse(data.body));
                });
            });
        }

        function disconnect() {
            if(stompClient !== null){
                stompClient.disconnect();//断开一个WebSocket连接
            }
            setConnected(false);
        }

        function sendName() {
            stompClient.send("/app/hi",{},JSON.stringify({'name':$("#name").val(),'content':$("#content").val()}));
        }

        function showHi(message) {
            $("#hi").append("<div>"+message.name+" : "+message.content + "</div>");
        }

        $(function () {
            $("#connect").click(function () {
                connect();
            });
            $("#disconnect").click(function () {
                disconnect();
            });
            $("#send").click(function () {
                sendName();
            });
        });
    </script>
</body>
</html>

效果:

css可以自己美化


番外语:

在http协议中,所有的请求都是客户端发起的,由服务端进行响应,服务端无法向客户端推送消息。

在一些IM应用中,需要服务端向客户端推送消息。

解决方案:

1.轮询

轮询,就是客户端在固定的时间间隔下不停的向服务器发送请求,查看服务端是否有最新的数据,若服务端有最新数据,则返回给客户端,反之返回一个空的json或者xml文档。

缺点:

客户端每次都要新建HTTP请求,服务端要处理大量的无效请求,在高并发场景下严重拖慢服务端的运行效率,服务端的资源也被浪费。

2.长轮询

是传统轮询的升级版。在长轮询中,服务端不是每次都立即响应客户端的请求,只有在服务端有最新数据的时候才立即响应客户端的请求,否则服务端会持有这个请求而不返回,直到有最新的数据时才返回。

缺点:

如果浏览器在服务器响应之前有新数据要发送,只能创建一个新的并发请求,or先尝试断掉当前请求,再创建新的请求。

TCP和HTTP规范中有连接超时。所谓的长轮询并不能一直持续,服务端和客户端的连接需要定期的连接和关闭再连接。

3.Applet和Flash

这2个技术都Out了。不过,他们以前可以让HTML更加绚丽,还解决消息推送问题。

使用Applet和Flash来模拟全双工通信,通过创建一个只有1像素点大小的透明的Applet or Flash,然后内嵌到网页中,再从Applet or Flash代码中创建一个Socket连接进行双向通信。消除了HTTP协议中的很多限制。当服务器有消息发送到客户端的时候,可以在Applet or Flash调用JS的Function将数据显示在页面上,当浏览器有数据要发送到服务器时也一样,通过Applet or Flash来传递,真正的实现了全双工通信。

缺点:

浏览器必须能运行Java orFlash.无论是Applet或者Flash都存在安全问题。随着H5的支持,Flash下架被提上日程(2020年正式停止支持Flash)

4.Websocket.

见文章首部说明。

发布了268 篇原创文章 · 获赞 36 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_39969226/article/details/103716832