42、JavaEE高级主题:WebSocket详解

news2025/4/18 15:15:09

WebSocket

一、WebSocket协议与实现

WebSocket是一种基于TCP协议的全双工通信协议,能够在客户端和服务器之间建立实时、双向的通信通道。通过WebSocket,客户端和服务器可以在任何时候发送数据,并立即接收到对方的响应。

1.1 WebSocket协议的特点

  • 全双工通信:客户端和服务器可以同时发送和接收消息。
  • 实时性:数据的传输是实时的,服务器可以主动推送数据给客户端。
  • 低延迟:相比HTTP协议,WebSocket的握手和数据传输延迟更低。
  • 高效性:WebSocket的数据帧格式简单,减少了数据传输的开销。

1.2 WebSocket的握手过程

WebSocket的连接建立需要通过HTTP协议的握手过程:

  1. 客户端请求:客户端发送一个HTTP请求,表示希望建立WebSocket连接。请求中包含Upgrade: websocketConnection: Upgrade头字段。
  2. 服务器响应:服务器返回一个HTTP响应,包含Upgrade: websocketConnection: Upgrade头字段,表示同意建立WebSocket连接。
  3. WebSocket连接建立:握手完成后,HTTP连接升级为WebSocket连接,客户端和服务器可以开始双向通信。

1.3 数据帧格式

WebSocket的数据帧格式如下:

 0                   1                   2                   3  
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3  
+-+-+-+-+-+-+  
|F|   RSV    |  OPCODE |   MASK   |   LENGTH     |  
+-+-+-+-+-+-+  
|                         PAYLOAD                     |  
+-+-+-+-+-+-+  
  • F: 最高位,表示是否是终端帧(FIN)。
  • RSV: 保留位,目前未使用。
  • OPCODE: 操作码,用于指示数据的类型。
  • MASK: 表示是否对负载数据进行了掩码处理。
  • LENGTH: 数据的长度。
  • PAYLOAD: 实际传输的数据内容。

1.4 心跳机制

为了保持连接的活性,WebSocket可以通过心跳机制定期发送心跳包,防止连接因长时间无数据传输而被关闭。

1.5 Java中的WebSocket实现

Java提供了两种方式来实现WebSocket:

  1. Java API for WebSocket (JSR-356):这是一个标准的Java API,提供了@ServerEndpoint@OnOpen@OnClose@OnError@OnMessage等注解,用于快速开发WebSocket应用。
  2. 第三方框架(如Spring WebSocket):Spring提供了更高级别的抽象,使得WebSocket的开发更加简单和灵活。

二、实时通信场景

WebSocket在以下场景中有广泛的应用:

2.1 实时聊天室

  • 点对点聊天:两个用户之间进行实时消息交流。
  • 群聊:多个用户加入同一个聊天室,消息可以广播给所有用户。
  • 消息记录:记录聊天历史,方便用户回顾。

2.2 在线监控系统

  • 实时数据推送:例如,服务器性能监控、物联网设备状态监控等。
  • 动态更新:客户端界面可以实时更新,例如股票价格、天气预报等。

2.3 其他场景

  • 在线游戏:支持玩家之间的实时交互。
  • 实时协作:例如,多人同时编辑文档或表格。
  • 通知系统:实时推送用户通知,例如邮件、消息提醒等。

三、实践1:实现实时消息功能

以下是一个基于Java API for WebSocket的简单聊天室示例:

3.1 服务端实现

import javax.websocket.OnClose;  
import javax.websocket.OnError;  
import javax.websocket.OnMessage;  
import javax.websocket.OnOpen;  
import javax.websocket.server.ServerEndpoint;  
import java.io.IOException;  
import java.util.concurrent.CopyOnWriteArrayList;  

@ServerEndpoint("/chat")  
public class ChatServer {  
    private static CopyOnWriteArrayList<ChatServer> clients = new CopyOnWriteArrayList<>();  

    @OnOpen  
    public void onOpen() {  
        clients.add(this);  
        System.out.println("新客户端连接");  
    }  

    @OnClose  
    public void onClose() {  
        clients.remove(this);  
        System.out.println("客户端断开");  
    }  

    @OnError  
    public void onError(Throwable throwable) {  
        System.out.println("发生错误:" + throwable.getMessage());  
    }  

    @OnMessage  
    public void onMessage(String message) {  
        System.out.println("收到消息:" + message);  
        broadcast(message);  
    }  

    private void broadcast(String message) {  
        for (ChatServer client : clients) {  
            try {  
                client.sendMessage(message);  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  

    private void sendMessage(String message) throws IOException {  
        // 向客户端发送消息  
        // 具体实现取决于底层的WebSocket库或框架  
    }  
}  

3.2 客户端实现

const websocket = new WebSocket('ws://localhost:8080/chat');  

websocket.onopen = function(event) {  
    console.log('连接到服务器');  
    websocket.send('客户端连接成功!');  
};  

websocket.onmessage = function(event) {  
    console.log('收到消息:' + event.data);  
    document.getElementById('chat-log').innerHTML += '<br>' + event.data;  
};  

websocket.onclose = function(event) {  
    console.log('连接关闭');  
};  

websocket.onerror = function(event) {  
    console.log('发生错误');  
};  

// 发送消息  
function sendMessage() {  
    const messageInput = document.getElementById('message');  
    const message = messageInput.value;  
    websocket.send(message);  
    messageInput.value = '';  
}  

四、实践2:在线实时监控系统

在上一部分中,我们实现了一个简单的实时聊天室功能。接下来,我们将探讨一个更复杂的案例:在线实时监控系统。在线监控系统是一种需要实时数据推送的典型场景,能够展示WebSocket在实际应用中的强大功能。


4.1 项目背景

假设我们需要开发一个实时监控系统,用于监控多台服务器的运行状态,包括:

  • CPU使用率
  • 内存使用率
  • 磁盘使用率
  • 网络带宽
  • 系统负载

此外,该系统需要支持以下功能:

  1. 实时数据推送:服务器状态数据实时更新。
  2. 历史数据查询:用户可以查看任意时间段内的服务器状态数据。
  3. 异常告警:当服务器状态超过阈值时,触发告警。
  4. 多客户端支持:支持多个客户端同时连接,并接收实时数据。

4.2 项目结构

我们将使用以下技术栈来实现这个系统:

  • 后端:使用Spring Boot框架,集成WebSocket来实现实时通信。(springboot框架没学过的看我的后续相关博文)
  • 前端:使用Vue.js来构建用户界面。
  • 数据库:使用MySQL存储历史数据。
  • 数据模拟:使用随机数生成模拟服务器状态数据(可替换为真实数据源)。

4.3 实现步骤

1. 项目初始化

创建一个Spring Boot项目,并引入以下依赖:

<dependencies>  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-websocket</artifactId>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-data-jpa</artifactId>  
    </dependency>  
    <dependency>  
        <groupId>mysql</groupId>  
        <artifactId>mysql-connector-java</artifactId>  
    </dependency>  
</dependencies>  

2. 数据模型

创建实体类ServerStatus,用于存储服务器状态数据:

@Entity  
public class ServerStatus {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;  
    
    private String serverName;  
    private Double cpuUsage;  
    private Double memoryUsage;  
    private Double diskUsage;  
    private Double networkBandwidth;  
    private Date timestamp;  
    
    // Getters and Setters  
}  

3. WebSocket服务端实现

创建WebSocket服务端,负责数据采集、推送和告警:

@Component  
@ServerEndpoint("/monitor")  
public class ServerMonitor {  
    private static final List<ServerMonitor> clients = new CopyOnWriteArrayList<>();  
    
    @Autowired  
    private ServerStatusService serverStatusService;  
    
    @OnOpen  
    public void onOpen() {  
        clients.add(this);  
        System.out.println("客户端连接成功");  
    }  
    
    @OnClose  
    public void onClose() {  
        clients.remove(this);  
        System.out.println("客户端断开连接");  
    }  
    
    @OnError  
    public void onError(Throwable throwable) {  
        System.out.println("发生错误:" + throwable.getMessage());  
    }  
    
    @OnMessage  
    public void onMessage(String message) {  
        System.out.println("收到消息:" + message);  
        // 处理客户端发送的消息(例如,客户端请求历史数据)  
        if (message.startsWith("query_history")) {  
            String serverName = message.split("_")[1];  
            List<ServerStatus> history = serverStatusService.getHistoryByServerName(serverName);  
            sendHistoryData(history);  
        }  
    }  
    
    public void broadcastStatus(ServerStatus status) {  
        String json = JSON.toJSONString(status);  
        for (ServerMonitor client : clients) {  
            try {  
                client.sendMessage(json);  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
    
    public void sendMessage(String message) throws IOException {  
        // 向客户端发送消息  
        // 消息格式:JSON格式的服务器状态数据  
        synchronized (this.session) {  
            this.session.getBasicRemote().sendText(message);  
        }  
    }  
    
    public void sendHistoryData(List<ServerStatus> history) {  
        String json = JSON.toJSONString(history);  
        for (ServerMonitor client : clients) {  
            try {  
                client.sendHistoryMessage(json);  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
    
    private void sendHistoryMessage(String json) throws IOException {  
        synchronized (this.session) {  
            this.session.getBasicRemote().sendText("history_" + json);  
        }  
    }  
}  

4. 数据采集和推送

创建一个定时任务,模拟服务器状态数据并推送:

@Component  
public class ServerDataCollector {  
    @Autowired  
    private ServerStatusService serverStatusService;  
    
    @Scheduled(fixedRate = 1000)  
    public void collectAndPushData() {  
        // 模拟服务器状态数据  
        List<ServerStatus> statuses = new ArrayList<>();  
        statuses.add(createServerStatus("Server-01"));  
        statuses.add(createServerStatus("Server-02"));  
        
        for (ServerStatus status : statuses) {  
            serverStatusService.saveStatus(status);  
        }  
        
        // 推送实时数据  
        for (ServerStatus status : statuses) {  
            new ServerMonitor().broadcastStatus(status);  
        }  
    }  
    
    private ServerStatus createServerStatus(String serverName) {  
        ServerStatus status = new ServerStatus();  
        status.setServerName(serverName);  
        status.setCpuUsage(Math.random() * 100);  
        status.setMemoryUsage(Math.random() * 100);  
        status.setDiskUsage(Math.random() * 100);  
        status.setNetworkBandwidth(Math.random() * 100);  
        status.setTimestamp(new Date());  
        return status;  
    }  
}  

5. 异常检测和告警

在数据采集后,添加异常检测逻辑:

@Service  
public class ServerStatusService {  
    @Autowired  
    private ServerStatusRepository repository;  
    
    public void saveStatus(ServerStatus status) {  
        repository.save(status);  
        checkThreshold(status);  
    }  
    
    public List<ServerStatus> getHistoryByServerName(String serverName) {  
        return repository.findByServerName(serverName);  
    }  
    
    private void checkThreshold(ServerStatus status) {  
        if (status.getCpuUsage() > 80) {  
            triggerAlarm("CPU使用率超过80%》,当前:" + status.getCpuUsage());  
        }  
        if (status.getMemoryUsage() > 85) {  
            triggerAlarm("内存使用率超过85%》,当前:" + status.getMemoryUsage());  
        }  
    }  
    
    private void triggerAlarm(String message) {  
        // 发送告警消息给客户端  
        new ServerMonitor().broadcastStatus(new ServerStatus());  
        // 其他处理逻辑,例如发送邮件、短信等  
    }  
}  

6. 前端实现

使用Vue.js创建实时监控界面:

<template>  
    <div class="monitor-container">  
        <div class="server-status" v-for="status in statuses" :key="status.serverName">  
            <h2>{{ status.serverName }}</h2>  
            <div class="metric-container">  
                <div class="metric">  
                    <label>CPU使用率</label>  
                    <div class="progress-bar">  
                        <div :style="{width: status.cpuUsage + '%'}"></div>  
                    </div>  
                    <span>{{ status.cpuUsage.toFixed(2) }}%</span>  
                </div>  
                <!-- 其他指标 -->  
            </div>  
        </div>  
    </div>  
</template>  

<script>  
export default {  
    data() {  
        return {  
            ws: null,  
            statuses: []  
        }  
    },  
    mounted() {  
        this.ws = new WebSocket('ws://localhost:8080/monitor');  
        this.ws.onmessage = (event) => {  
            if (event.data.startsWith("history_")) {  
                this.historyData = JSON.parse(event.data.split("history_")[1]);  
            } else {  
                this.statuses = JSON.parse(event.data);  
            }  
        };  
    }  
}  
</script>  

4.4 功能说明

  1. 实时数据推送:后端定时生成模拟数据并通过WebSocket推送到客户端,客户端实时更新界面。
  2. 历史数据查询:客户端可以通过发送特定的消息(如query_history_Server-01)来查询任意时间段的历史数据。
  3. 异常告警:当服务器状态超过阈值时,后端触发告警,并通过WebSocket通知客户端。
  4. 多客户端支持:WebSocket协议支持多个客户端同时连接,并接收实时数据。

4.5 总结

通过这个复杂的案例,我们展示了如何利用WebSocket协议实现实时监控系统。该系统不仅支持实时数据推送,还结合了历史数据查询、异常告警等功能,体现了WebSocket在实时通信中的强大能力。

这种架构可以扩展到更多复杂场景,例如:

  • 集成更多监控项(如网络延迟、请求响应时间等)
  • 支持多种数据可视化方式(如曲线图、柱状图等)
  • 提供更完善的安全认证机制
  • 支持多种终端(如移动端、桌面端等)

五、总结

WebSocket是一种强大的协议,能够实现客户端和服务器之间的实时、双向通信。它在实时聊天、在线监控、游戏开发等场景中有广泛的应用。本节通过理论和实践相结合的方式,介绍了WebSocket的核心概念、实现方式以及实际应用场景。通过学习本节内容,可以掌握WebSocket的基本使用方法,并能够在实际项目中应用它。

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

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

相关文章

Http代理服务器选型与搭建

代理服务器选型-Squid 缓存加速 缓存频繁访问的网页、图片等静态资源&#xff0c;减少对原始服务器的重复请求&#xff0c;提升响应速度支持HTTP、HTTPS、FTP等协议&#xff0c;通过本地缓存直接响应客户端请求 访问控制 基于ACL&#xff08;访问控制列表&#xff09;实现精细…

Linux主要开发工具之gcc、gdb与make

此系列还有两篇&#xff0c;大家想完整掌握可以阅读另外两篇 Linux文本编辑与shell程序设计-CSDN博客 Linux基础知识详解与命令大全&#xff08;超详细&#xff09;-CSDN博客 1.gcc编译系统 1.1 文件名后缀 文件名后缀 文 件 类 型 文件名后缀 文 件 类 型 .c C源…

C++初阶-C++入门基础

目录 ​编辑 1.C的简介 1.1C的产生和发展 1.2C的参考文档 1.3C优势和难度 1.4C学习的建议 2.C的第一个程序 2.1打印Hello world 2.2头文件 2.3namespace命名空间 2.4&#xff1a;&#xff1a;作用域限定符 2.5namespace的延伸 2.6C的输入输出 3.总结 1.C的简介 …

idea手动创建resources文件夹

有时maven没有构建成功可能造成&#xff0c;resources文件夹不创建的现象 此时我们可以手动创建 手动创建

第十五届蓝桥杯大赛软件赛省赛Python 大学 C 组题目试做(中)【本期题目:回文数组,挖矿】

OK&#xff0c;继续写我们的第十五届蓝桥杯大赛软件赛省赛Python 大学 C 组题目&#xff0c;后面的题目比较麻烦了&#xff0c;所以我们再分两期讲。 这一期的题有 &#xff1a; 回文数组&#xff0c;挖矿 文章目录 回文数组基本思路第一步&#xff0c;获取半个数组每个数需要…

Qt动画 QAbstractAnimation

文章目录 简介QVariantAnimation 数值动画QPropertyAnimation 属性动画 QAnimationGroup 一组动画QParallelAnimationGroup 并行动画组QSequentialAnimationGroup 串行动画组 简介 QAbstractAnimation 是所有 Qt 动画的基类。 该类定义了所有动画应该都会有的功能函数。 要想实…

SpringMvc的请求-获得请求参数

客户端请求参数的格式是: namevalue&namevalue..… 服务器端要获得请求的参数&#xff0c;有时还需要进行数据的封装&#xff0c;SpringMVC可以接收如下类型的参数: 基本类型参数 POJO类型参数 数组类型参数 集合类型参数 获得基本类型参数 Controller中的业务方法…

flutter开发音乐APP(前提准备)

1、项目的一些环境&#xff1a; 2、接口文档&#xff1a; 酷狗音乐 NodeJS 版 API 3、接口数据结构化 Instantly parse JSON in any language | quicktype UI样式借鉴参考&#xff1a; Coffee-Expert/Apple-Music-New-UI: Apple Music Clone on Flutter, with redesigned UI…

使用docker搭建redis镜像时云服务器无法访问到国外的docker官网时如何解决

下载redis镜像 docker redis:版本号 此时截图中无法访问到国外的docker官网 解决方案&#xff1a; 通过更换镜像源来正常下载redis镜像 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<EOF {"registry-mirrors": ["https://docker.1…

双引擎驱动:解密音视频体验的QoS技术底座与QoE感官革命

QoS 定义&#xff1a;QoS&#xff08;Quality of Service&#xff0c;服务质量&#xff09;衡量音视频传输技术层面的性能表现&#xff0c;聚焦网络传输和系统处理能力&#xff0c;通过客观指标量化服务质量。核心指标 码率/带宽&#xff1a;数据传输速率上限&#xff0c;直接…

pom导包成功,但是就是无法使用相关类,同时报错:Library:Maven ‘xxx‘ has broken path

开发环境&#xff1a;Intellij 2023 一、问题记录 在maven工程的pom文件导入如下某一依赖(JGit)。没有显示导包的错误&#xff0c;同时在maven仓库里面找到对应的包是正常下载到相应jar的。 但是就是无法引入相关的类。打开Project Structure&#xff0c;在Dependencies中发现…

mysql的下载和安装2025.4.8

mysql下载和安装 MySQL的下载网址&#xff1a; https://www.mysql.com/downloads/ 点击进入Windows版本下载&#xff1a;我们可以选择需要的MySQL版本以及所需的操作系统&#xff0c;这里选择离线安装&#xff1a; 注意&#xff1a;MySQL 8.0 是带有 MySQL Installer 的最后一…

QML Loader:延迟加载与动态切换

目录 引言相关阅读工程结构LoaderDelay.qml - 延迟加载实现完整代码HeavyComponent.qml代码解析运行效果 LoaderSwitch.qml - 动态切换组件完整代码代码解析运行效果 Main.qml - 主界面实现完整代码主界面结构代码解析 总结下载链接 引言 QML的Loader组件提供了一种强大的机制…

Spark Core编程

一 Spark 运行架构 1 运行架构 定义 Spark 框架的核心是一个计算引擎&#xff0c;整体来说&#xff0c;它采用了标准 master-slave 的结构 如图所示 2 核心组件 Spark 框架有两个核心组件: 1)Driver 2)Spark 驱动器节点&#xff08;用于执行 Spark 任务中的 main 方法&…

无人机装调与测试

文章目录 前言一、无人机基本常识/预备知识&#xff08;一&#xff09;无人机飞行原理无人机硬件组成/各组件作用1.飞控2.GPS3.接收机4.电流计5.电调6.电机7.电池8.螺旋桨9.UBEC&#xff08;稳压模块&#xff09; &#xff08;二&#xff09;飞控硬件简介&#xff08;三&#x…

【图书管理系统】全栈开发图书管理系统获取图书列表接口(后端:计算图书页数、查询当前页展示的书籍)

图书列表 实现服务器代码(计算图书总数量查询当前页需要展示的书籍) 后端响应时&#xff0c;需要响应给前端的数据 records&#xff1a;第 pageNum 页要展示的图书有哪些&#xff08;存储到List集合中&#xff09;total&#xff1a;计算一共有多少本书&#xff08;用于告诉前…

正则表达式补充——python

简介 本章是对前面正则表达式的补充。 一、复杂的查找替换等任务 content 张三是脑卒中病 李四&#xff0c;是高血脂 苏齐&#xff0c;是肺结核病 六六&#xff0c;是血血血血import re p re.compile(r...病) for one in p.findall(content):print(one) 运行结果&#xf…

[ctfshow web入门] web7

信息收集 题目提示&#xff1a;版本控制很重要&#xff0c;但不要部署到生产环境更重要。 那么很有可能&#xff0c;版本控制相关的信息被部署到环境了&#xff0c;比如比如version.txt记录了一些相关配件的版本&#xff0c;git版本管理工具中的.git文件夹未删除 信息收集就是…

DeepSeek-V3 API:开启下一代AI应用开发的新篇章

引言 在人工智能技术日新月异的今天&#xff0c;大型语言模型(LLM)正以前所未有的速度改变着我们与技术互动的方式。DeepSeek-V3作为国内领先的大语言模型之一&#xff0c;其API的开放为开发者提供了强大的AI能力集成方案。 DeepSeek-V3 API的核心优势 1.强大的语言理解与生…

go语言应该如何学习

以下是学习Go语言的高效路径及关键技巧&#xff0c;结合多个优质来源整理而成&#xff0c;适合不同基础的学习者&#xff1a; 一、基础语法快速入门&#xff08;1-2周&#xff09; 1、环境搭建 下载安装Go SDK&#xff0c;配置GOPATH和GOROOT环境变量&#xff0c;推荐使用Go…