【后端】websocket学习笔记


参考视频
【后端&网络&大数据&数据库目录贴】

1. 消息推送常见方式

  • 轮询
  • 长轮询
  • websocket
  • SSE

1.1 轮询 VS 长轮询

在这里插入图片描述

1.2 SSE(server-sent event)服务器发送事件

  • SSE在服务器和客户端之间打开一个单向通道
  • 服务端响应的不再是一次性的数据包,而是text/event-stream类型的数据流信息
  • 服务器有数据变更时将数据流式传输到客户端
    在这里插入图片描述

2. websocket介绍

2.1 介绍

websocket是一种基于TCP链接上进行全双工通信的协议

  • 全双工:允许数据在两个方向上同时传输。(TCP是全双工,HTTP是基于TCP的)
  • 半双工:允许数据在两个方向上传输,但是同一个时间段内只允许一个方向上传输。
    在这里插入图片描述

2.2 原理

在这里插入图片描述

  • ws://localhost?chat 依然是http协议
  • Connection:UpgradeUpgrade: websocket表明连接升级
  • 响应码 101说明已经切换成功

2.3 websoket API

2.3.1 客户端【浏览器】API

  • websocket对象创建
let ws=new WebSocket(URL);
  • websocket对象相关事件
    在这里插入图片描述
  • websocket对象提供的方法
    在这里插入图片描述

2.3.2 服务端API

在这里插入图片描述

  • 服务端如何接收客户端发送的数据呢?
    在这里插入图片描述
  • 服务端如何推送数据给客户端呢?
    在这里插入图片描述

3. 代码实现

3.1 流程分析

在这里插入图片描述

3.2 pom依赖

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

3.3 配置类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.4 消息格式

在这里插入图片描述

3.5 消息类

@ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfigurator.class)
@Component
public class ChatEndpoint {
    public static final Map<String, Session> sessionsMap = new ConcurrentHashMap<>();
    private HttpSession httpSession;

    /**
     * 建立websocket连接后,被调用
     *
     * @param session
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        //1.将session进行保存
        this.httpSession = (HttpSession) config.getUserProperties().get("httpSession");
        String userName = (String) httpSession.getAttribute("userName");

        ChatEndpoint.sessionsMap.put(userName, session);
        //2. 广播消息,需要将登录的所有的用户推送给所有用户
        String sendMessage = MessageUtil.sendMessage(true, null, userName + "上线");
        boardcast(sendMessage);
    }

    /**
     * 广播消息
     */
    private void boardcast(String message) {
        // 遍历 map 集合
        Set<Map.Entry<String, Session>> entries = ChatEndpoint.sessionsMap.entrySet();
        for (Map.Entry<String, Session> entry : entries) {
            Session session = entry.getValue();
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                // 记录日志
            }
        }
    }

    @OnMessage
    public void onMessage(String message) {
        try {
            String fromName = (String) this.httpSession.getAttribute("userName");
            // 将消息推送给指定的用户   message : {"toName":"张三","message":"你好"}
            ClientMessage clientMessage = JSON.parseObject(message, ClientMessage.class);
            Session session = ChatEndpoint.sessionsMap.get(clientMessage.getToName());
            String sendMessage = MessageUtil.sendMessage(false, fromName, clientMessage.getMessage());
            session.getBasicRemote().sendText(sendMessage);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 当websocket连接断开时,此方法会被处罚
     */
    @OnClose
    public void onClose(Session session) {
// 从在线用户集合中剔除断开连接的用户
        String userName = (String) this.httpSession.getAttribute("userName");
        ChatEndpoint.sessionsMap.remove(userName);
        // 通知其他用户当前用户下线
        String sendMessage = MessageUtil.sendMessage(true, null, userName + "上线");
        boardcast(sendMessage);
    }
}

4. 前端代码(非视频源码)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/jquery.min.js"></script>
</head>
<body>
<p>【fromUserId】:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>【toUserId】:<div><input id="toUserId" name="toUserId" type="text" value="20"></div>
<p>【发送的消息】:<div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【收到的内容】:<div><textarea id="receText"></textarea></div>
  <button id="openSocket">开启socket</button>
  <button id="sendMessage">发送消息</button>
  <button id="closeWs">关闭连接</button>
<script>
    $(function (){
        console.log('加兹阿勒')
        const urlParams = new URLSearchParams(window.location.search);
        console.log(urlParams)
        var fromUserId = urlParams.get('fromUserId');
        $('#userId').val(fromUserId)
    })


    var ws ;
    function openSocket() {
        if(typeof(WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        }else{
            console.log("您的浏览器支持WebSocket");
            //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
            //等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
            //var socketUrl="${request.contextPath}/im/"+$("#userId").val();
            var socketUrl="http://localhost:8081/chat";
            socketUrl=socketUrl.replace("https","wss").replace("http","ws");
            console.log(socketUrl);
            if(ws !=null){
                ws .close();
                ws =null;
            }
            ws = new WebSocket(socketUrl);
            // 当 WebSocket 成功建立连接时触发
            ws.onopen  = function(event) {
                console.log("WebSocket is connected now.");
                // 在这里你可以发送一些初始消息到服务器
                // ws.send("Hello, Server!");
            };

            // 当接收到来自服务器的消息时触发
            ws.onmessage = function(event) {
                console.log("Received data from server: " + event.data);
                // 处理从服务器接收到的数据
                var parse = JSON.parse(event.data);
                $('#receText').val(parse.message);
            };

            // 当 WebSocket 连接关闭时触发
            ws.onclose = function(event) {
                if (event.wasClean) {
                    console.log("WebSocket connection closed cleanly, code=" + event.code + " reason=" + event.reason);
                } else {
                    // 例如,服务器进程被终止而关闭
                    console.log("WebSocket connection died");
                }
            };

            // 当 WebSocket 连接出现错误时触发
            ws.onerror = function(error) {
                console.error("WebSocket Error: " + error);
            };
        }
    }
    function sendMessage() {
        if(typeof(WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        }else {
            console.log("您的浏览器支持WebSocket");
            console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
            ws.send('{"toName":"'+$("#toUserId").val()+'","message":"'+$("#contentText").val()+'"}');
        }
    }
    function closeWs(){
        ws.close();
    }
    $("#openSocket").on('click', openSocket);
    $("#sendMessage").on('click',sendMessage);
    $("#closeWs").on('click', closeWs);
</script>
</body>
</html>
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值