WebSocket详解以及应用

news2024/9/25 17:18:41
  • 😜           :是江迪呀
  • ✒️本文关键词websocket网络长连接前端
  • ☀️每日   一言任何一个你不喜欢而又离不开的地方,任何一种你不喜欢而又无法摆脱的生活,都是监狱!

在这里插入图片描述

一、前言

我们在日常开发中是否会思考,为什么一个系统在没有任何请求的前提下,会接受到服务器端发来的消息?聊天软件是为什么可以做到消息的发送和实时接收?网络游戏中为什么我可以在我们屏幕中看到其它玩家的操作?今天这篇关于WebSocket的文章完全可以解决你的疑问。废话不多说,让我们开始吧!

二、Websocket介绍

2.3 什么是Websocket?

WebSocket是一种全双工通信协议,它能够在单个TCP连接上实现 双向、持久的实时通信, 无需频繁地发起连接和关闭连接。通过WebSocket,我们可以在浏览器和服务器之间建立稳定的连接,实时传递数据实现即时聊天实时更新多人在线游戏等功能。

2.2 Websocket的特点

(1)双向通信: WebSocket允许客户端和服务器之间进行双向通信,无需等待对方的请求或响应。

(2) 持久连接: WebSocket连接一旦建立,会持续保持连接状态,避免了重复的连接和断开过程,减少了网络开销。

(3)低延迟: 由于连接一直保持打开状态,数据的传输可以更快地实现,从而实现低延迟的实时通信。

(4) 较少的数据传输量: 与传统的HTTP请求相比,WebSocket传输的数据头部信息较少,减少了数据传输量,提高了效率。

(5) 协议支持: WebSocket是一种独立于应用层协议的协议,可以在多种编程语言和平台上使用。

2.3 WebsocketHttp区别

(1)通信方式区别:

  • Http是请求-响应式的协议: 客户端发送请求,服务器返回响应,然后连接断开。这种方式适合传输静态内容或需要客户端不断向服务器发起请求的情况。
  • Websocket是全双工的通信协议WebSocket允许在客户端和服务器之间建立持久性的连接,双方可以随时相互发送数据。这种方式适合实时性要求较高、交互复杂的应用,如实时聊天、在线游戏等。
    (2)连接状态区别:
  • Http是短连接:web端请求服务器端建立连接,服务器端返回后连接断开。
  • Websocket是长连接:连接一次,就会一直保持连接。

Http相当于写信,需要一来一回。
Websocket相当于打电话,只要不挂断,咱们可以一直通话。

三、实现方式

我采用**客户端-Client服务器端-Service**的方式来展示WebSocket的实现方式。客户端使用JS实现服务器端使用Java + SpringBoot来实现。

3.1 客户端

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Websocket</title>
	</head>
	<body>
		
		<input id="messageInput" placeholder="消息">
		<button id="sendButton">发送</button>
		
	</body>
</html>
<script>
	// url 路径最后的 1 表示是那个客户端
	const websocket = new WebSocket('ws://192.168.31.136:5050/websocket/1');
	websocket.onmessage = event => {
	    const data = JSON.parse(event.data);
	    // 处理服务器发送过来的消息
	    console.log('Received message:', data);
	};
	sendButton.addEventListener('click', () => {
	    const message = messageInput.value;
	    const messageData = {
	        message: message
	    };
		//发送消息到服务端
	    websocket.send(JSON.stringify(messageData));
	    messageInput.value = ''; // 清空输入框
	});
	
	
	window.addEventListener('beforeunload', () => {
	    // 在页面关闭前关闭 WebSocket 连接
	    websocket.close();
	});
</script>

3.2 服务器端

引入依赖:

<!--SpringBoot依赖-->
 <dependency>
    <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
     <version>2.1.2.RELEASE</version>
 </dependency>
 <!--Websocket依赖-->
 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-websocket</artifactId>
      <version>2.3.7.RELEASE</version>
</dependency>

SpringBoot启动类:

@SpringBootApplication
@EnableWebSocket
public class ApplicationRun {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationRun.class,args);
    }
}

这里注意一定要添加上@EnableWebSocket,表示开启Websocket

application.ymal配置文件:

server:
  port: 5050

Websocket服务端:

package com.hjd.websocket.websocketserver;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/websocket/{clientId}")
@Slf4j
public class MsgWebSocketServer {
    /**
     * 连接成功后会调用的方法
     */
    @OnOpen
    public void webSocketOpen(@PathParam("clientId") String clientId) {
        log.info("客户端{}连接上了服务端:", clientId);
    }

    /**
     * 关闭连接会调用方法
     * 关闭方法在服务器端停止或者是客户端页面关闭时都会被调用。
     * 或者是客户端调用了关闭链接的方法。
     */
    @OnClose
    public void onClose() {
        log.info("有客户端断开了连接!");
    }

    /**
     * 接收到消息会调用的方法
     */
    @OnMessage
    public void onMessage(@PathParam("clientId") String clientId,String message) {
        log.info("客户端:{}发来了消息:{}",clientId,message);
    }

    /**
     * 出现错误时调用的方法
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("服务器端发生了错误!");
    }

}

3.3 测试 - 客户端发消息给服务器端

我们运行客户端在浏览器。
在这里插入图片描述

我们可以看到服务器端打印了如下日志:
在这里插入图片描述
表示已经连接上了。

客户端发送消息给服务器端:

在这里插入图片描述
服务器端接收到了消息:

在这里插入图片描述

3.4 测试- 服务器端推送信息给客户端

要想服务器端推送消息给客户端,有个问题是服务器端如何知道你要发送给那个客户端呢?所以就必须存储下已经连接到服务器端客户端消息。需要改动下代码:
Websocket服务端(省略了onErroronClose方法它们不变):

@Component
@ServerEndpoint("/websocket/{clientId}")
@Slf4j
public class MsgWebSocketServer {

    /**
     * 用来存放已经成功连接到服务器端的客户端
     */
    private static ConcurrentHashMap<String, MsgWebSocketServer> webSocketSet = new ConcurrentHashMap<>();
    private Session session;

    /**
     * 客户端标识
     */
    private String clientId;

    /**
     * 连接成功后调用的方法
     */
    @OnOpen
    public void webSocketOpen(Session session,@PathParam("clientId") String clientId) {
        this.saveClient(session,clientId);
        log.info("客户端:{}连接上了服务端", clientId);
    }
    @OnMessage
    public void onMessage(@PathParam("clientId") String clientId,String message,@PathParam("toClientId") String toClientId) throws Exception {
        log.info("客户端:{}发来了消息:{}",clientId,message);

        //给指定的客户端推送消息
        if(toClientId != null){
            webSocketSet.get(toClientId).sendMessage(message);
        }
    }
    /**
     * 保存客户端
     * @param session
     * @param clientId
     */
    private void saveClient(Session session,String clientId){
        this.session = session;
        this.clientId = clientId;
        if (webSocketSet.containsKey(clientId)) {
            webSocketSet.remove(clientId);
            webSocketSet.put(clientId, this);
        } else {
            webSocketSet.put(clientId, this);
        }
    }

    /**
     * 发送消息
     * @param message
     * @throws Exception
     */
    private void sendMessage(String message) throws Exception {
        this.session.getBasicRemote().sendText(message);
    }
}

使用调接口的方式,触发服务器推送消息动作:

package com.hjd.websocket.controller;

import com.hjd.websocket.websocketserver.MsgWebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.websocket.server.PathParam;

@RequestMapping("/send")
@RestController
public class WebSocketController {
    @Autowired
    private MsgWebSocketServer msgWebSocketServer;

    /**
     * 发送消息给指定客户端
     * @param msg
     * @param toClient
     * @throws Exception
     */
    @GetMapping("/sendMsgToClient/{msg}")
    public void getIndex(@PathParam("msg") String msg,@PathParam("toClient") String toClient) throws Exception {
        msgWebSocketServer.onMessage(null,msg,toClient);
    }

}

调用推送消息接口:

http://localhost:5050/send/sendMsgToClient?msg=%22%E5%93%88%E5%93%88%E5%93%88%E5%93%88%22&toClient=1

客户端控制台:
在这里插入图片描述

3.5 测试 - 广播给所有客户端

这个也非常简单,我们已经把连接上的客户端全部存储到了ConcurrentHashMap集合中(之所以使用ConcurrentHashMap是因为它线程安全,可以保证再多个客户端链接时,存储的信息不会错乱)只需要遍历下集合,给每个客户端都发送消息即可实现广播的效果了。

四、应用

4.1 聊天室

基于上面的讲解,我们在客户端发送消息时指定下接受消息的toClient就搞定了。

4.2 多人网络游戏

这个思路也比较简单,不过得分房间,比如一个房间内有四个玩家,其中一个玩家操作了游戏中的对象,只需要将对应的操作指令发送给服务器端,然后广播房间内的所有玩家,那么就可以实现游戏世界的状态同步,让玩家能够看到其他玩家的操作了。

4.3 服务器推送

3.5测试演示的就是。

总结

最后通过一张图来说明吧!
在这里插入图片描述
我想使用Websocket实现一个多人在线游戏作为示例更加充分的说明Websocket的应用。等我吃60个汉堡再说吧~!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/930219.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

定州市社会保险待遇手机app-定州社会保障

社会保险的缴纳主要包括养老保险、医疗保险、生育保险&#xff0c;单位职工还有工伤保险和失业保险的缴纳&#xff0c;社会保险的缴纳一般都在当地人力资源和社会保障部门&#xff0c;在定州&#xff0c;社会保险登记的流程是怎样走的&#xff1f;下面由法律指南小编为大家解答…

改进YOLO系列:6.添加ECA注意力机制

添加ECA注意力机制 1. ECA注意力机制论文2. ECA注意力机制原理3. ECA注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. ECA注意力机制论文 论文题目:ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks 论文链接:ECA-N…

oracle 12c怎样修改varchar2允许的最大长度

12C单实例测试&#xff0c;varchar2在早期版本中最大长度限制为4000&#xff0c;当字段长度指定的比较长的时候会报错&#xff1a;ORA-00910: specified length too long for its datatype。 早期版本中虽然SQL数据类型限制为4000&#xff08;如表中的列的varchar2类型&#x…

抖音web频道爬虫

抖音web频道爬虫代码&#xff1a; <?php header(Content-Type:application/json; charsetutf-8);//抖音频道爬虫class DouyinChannel{private $app_id 1;private $spider_code 1;private $channels [["channel_name" > "热点","url"…

Java实现自定义注解

前言 &#xff08;1&#xff09;Java实现自定义注解其实很简单&#xff0c;跟类定义差不多&#xff0c;只是属性的定义可能跟我们平时定义的属性略有不同&#xff0c;这里会给大家详解&#xff0c;先来看代码&#xff1a; Target(ElementType.FIELD) Retention(RetentionPoli…

iOS App的设计规范

iOS App 的设计规范是苹果公司为开发人员和设计师提供的一系列准则和建议&#xff0c;旨在确保应用在 iOS 设备上的外观、交互和用户体验保持一致。以下是一些常见的 iOS App 设计规范要点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包…

LEADTOOLS V22 for Python -Crack

LEAD Technologies Inc 是面向所有主要平台和编程语言的应用程序开发的人工智能 SDK 的领先提供商&#xff0c;很高兴地宣布在其最新的 LEADTOOLS 版本 22 更新中添加了完整的 Python 支持。 Python是一种动态的高级编程语言&#xff0c;广泛应用于科学计算、数据分析、人工智…

似懂非懂的 AspectJ

今天想和小伙伴们聊一下我们在使用 Spring AOP 时&#xff0c;一个非常常见的概念 AspectJ。 1. 关于代理 小伙伴们知道&#xff0c;Java 23 种设计模式中有一种模式叫做代理模式&#xff0c;这种代理我们可以将之称为静态代理&#xff0c;Spring AOP 我们常说是一种动态代理…

R语言常用基本函数,含实例:万字总结

目录 vector:创建向量&#xff08;默认填充0&#xff0c;空字符&#xff0c;FALSE&#xff09; data.frame :可以看作由多个向量组成的表格&#xff0c;每个向量代表表格的一列数据 sequence:创建序列(可以简写为seq) dim:获取矩阵或数组的维度信息 length subset&#x…

优思学院|传统流水线生产与单元式生产的差异与优势对比

在制造业领域&#xff0c;生产方式的选择对于生产效率和产品质量至关重要。传统流水线生产和精益生产中的单元式生产是两种常见的生产模式&#xff0c;它们在工作方式、优势以及适用情境上存在着显著的差异。本文将对传统流水线生产和单元式生产进行比较&#xff0c;并探讨它们…

“探索Spring与MyBatis集成的最佳实践与技巧“

目录 引言&#xff1a;1.Spring与MyBatis集成的基本配置2.Spring aop集成pagehelper插件总结附带内容&#xff1a; 引言&#xff1a; 在现代的软件开发中&#xff0c;Spring和MyBatis是两个非常流行的框架。Spring提供了强大的依赖注入和面向切面编程的功能&#xff0c;而MyBa…

炫酷前端页面,鼠标点击特效

最近发现了两个好看的鼠标点击特效&#xff0c;收藏起来用作学习使用&#xff0c;以及更方便的利用 一、鼠标点击弹出爱心 效果图 html源码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><m…

应知道的python基础知识

1、运算符 2、特殊情况下的逻辑运算 3、循环中的else 3.1 while else 3.2 for else 4、列表相关操作 列表的相关操作 4.1增(append, extend, insert) 通过append可以向列表添加元素:列表.append(新元素数据)通过extend可以将另一个列表中的元素逐一添加到列表中:列表.exte…

【推荐】Spring与Mybatis集成

目录 1.概述 2.集成 2.1代码演示&#xff1a; 3.整合 3.1概述 3.2 进行整合分页 接着上两篇&#xff0c;我已经写了Mybatis动态之灵活使用&#xff0c;mybatis的分页和特殊字符的使用方式接下来把它们集成起来&#xff0c;是如何的呢&#x1f447;&#x1f447;&#x1…

深入理解linux内核--系统启动

史前时代&#xff1a;BIOS 计算机在加电的那一刻几乎是毫无用处的&#xff0c;因为RAM芯片中包含的是随机数据&#xff0c;此时还没有操作系统在运行。 在开始启动时&#xff0c;有一个特殊的硬件电路在CPU的一个引脚上产生一个RESET逻辑值。 在RESET产生以后&#xff0c;就把…

pytorch学习(7)——神经网络优化器torch.optim

1 optim 优化器 PyTorch神经网络优化器&#xff08;optimizer&#xff09;通过调整神经网络的参数&#xff08;weight和bias&#xff09;来最小化损失函数&#xff08;Loss&#xff09;。 学习链接&#xff1a; https://pytorch.org/docs/stable/optim.html 1.1 优化器基类 使…

Wlan——无线桥接的基本概念及配置

目录 WDS无线分布式系统 WDS组网拓扑 中继桥接 一对一桥接 一对多桥接 多跳桥接 锐捷无线桥接的配置 根桥的配置(瘦AP是在AC上配置) 非根桥的配置&#xff08;直接在AP上配置&#xff09; WDS无线分布式系统 WDS指AP之间通过无线链路连接两个或多个独立的局域网&…

picGo+gitee+typora设置图床

picGogiteetypora设置图床 picGogitee设置图床下载picGo软件安装picGo软件gitee操作在gitee中创建仓库在gitee中配置私人令牌 配置picGo在插件设置中搜索gitee插件并进行下载 TyporapicGo设置Typora 下载Typora进行图像设置 picGogitee设置图床 当我了解picGogitee可以设置图床…

每日两题 129求根节点到叶节点数字之和 257二叉树的所有路径

129 题目 给你一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字&#xff1a; 例如&#xff0c;从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。 计算从根节点到叶节点生成的 所有…

pytestx容器化执行引擎

系统架构 前端、后端、pytest均以Docker容器运行服务&#xff0c;单独的容器化执行引擎&#xff0c;项目环境隔离&#xff0c;即用即取&#xff0c;用完即齐&#xff0c;简单&#xff0c;高效。 前端容器&#xff1a;页面交互&#xff0c;请求后端&#xff0c;展示HTML报告 后…