WebSocket和长轮询

server/2025/3/18 13:52:01/

WebSocket 原理与实现

原理

WebSocket 是一种在单个TCP连接上进行全双工通信的协议。它允许服务器主动向客户端推送数据,而不需要客户端发起请求。一旦连接建立,客户端和服务器可以随时互相发送消息。

  1. 握手阶段:客户端通过HTTP请求升级到WebSocket协议。
  2. 数据传输阶段:一旦握手成功,双方可以通过TCP连接进行双向通信。
  3. 关闭阶段:当不再需要通信时,任意一方可以关闭连接。
实现步骤
  1. 添加依赖:在pom.xml中添加Spring Boot WebSocket依赖。
  2. 配置WebSocket:创建一个配置类来注册WebSocket处理器。
  3. 实现处理器:创建一个处理器类来处理WebSocket消息。
  4. 启动应用:创建Spring Boot启动类。
  5. 前端页面:编写HTML页面,使用JavaScript与WebSocket服务器进行通信。
代码示例
后端( Spring Boot)
java">package com.example.websocketdemo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*");}
}package com.example.websocketdemo.handler;import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import java.io.IOException;
import java.util.HashSet;
import java.util.Set;public class MyWebSocketHandler extends TextWebSocketHandler {private final Set<WebSocketSession> sessions = new HashSet<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {System.out.println("客户端已连接: " + session.getId());sessions.add(session);}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {System.out.println("收到消息: " + message.getPayload());for (WebSocketSession sess : sessions) {try {sess.sendMessage(new TextMessage("服务器已收到: " + message.getPayload()));} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {System.out.println("客户端已断开连接: " + session.getId());sessions.remove(session);}
}package com.example.websocketdemo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class WebSocketDemoApplication {public static void main(String[] args) {SpringApplication.run(WebSocketDemoApplication.class, args);}
}
前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>WebSocket 示例</title>
</head>
<body><h1>WebSocket 示例</h1><input type="text" id="messageInput" placeholder="输入消息"><button onclick="sendMessage()">发送消息</button><div id="messages"></div><script>const socket = new WebSocket('ws://localhost:8080/ws');socket.addEventListener('open', function (event) {console.log('已连接到服务器');});socket.addEventListener('message', function (event) {console.log('收到消息:', event.data);document.getElementById('messages').innerHTML += `<p>${event.data}</p>`;});function sendMessage() {const input = document.getElementById('messageInput');const message = input.value;if (message.trim()) {socket.send(message);input.value = '';}}</script>
</body>
</html>

长轮询 原理与实现

原理

长轮询是一种模拟服务器推送的技术。客户端向服务器发送一个请求,服务器会保持这个连接打开,直到有新的数据可用或者超时。一旦服务器返回响应,客户端立即再次发起请求以保持连接。

  1. 客户端发起请求:客户端发送HTTP请求到服务器。
  2. 服务器等待数据:服务器保持连接打开,直到有新数据或超时。
  3. 服务器返回响应:一旦有新数据或超时,服务器返回响应。
  4. 客户端处理响应并重新发起请求:客户端处理响应并立即发起新的请求。
实现步骤
  1. 创建控制器:编写一个控制器来处理长轮询请求和数据更新请求。
  2. 启动应用:创建Spring Boot启动类。
  3. 前端页面:编写HTML页面,使用JavaScript发起长轮询请求和发送更新数据。
代码示例
后端(Spring Boot)
java">package com.example.longpollingdemo.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;@RestController
public class LongPollingController {private final ConcurrentHashMap<String, String> dataStore = new ConcurrentHashMap<>();private final Object lock = new Object();@GetMapping("/poll")public String poll(@RequestParam(value = "timeout", defaultValue = "5000") long timeout) throws InterruptedException {synchronized (lock) {if (dataStore.isEmpty()) {lock.wait(timeout);  // 等待新数据或超时}return dataStore.pollFirstEntry().getValue();  // 返回第一条数据并移除}}@PostMapping("/update")public String update(@RequestParam String data) {synchronized (lock) {dataStore.put("latest", data);  // 存储新数据lock.notifyAll();  // 通知等待的线程}return "数据更新成功";}
}package com.example.longpollingdemo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class LongPollingDemoApplication {public static void main(String[] args) {SpringApplication.run(LongPollingDemoApplication.class, args);}
}
前端(HTML + JavaScript)
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>长轮询 示例</title>
</head>
<body><h1>长轮询 示例</h1><button onclick="sendUpdate()">发送更新</button><div id="messages"></div><script>let polling = false;function pollServer() {if (!polling) {polling = true;fetch('/poll?timeout=5000').then(response => response.text()).then(data => {document.getElementById('messages').innerHTML += `<p>收到数据: ${data}</p>`;polling = false;pollServer();  // 立即发起新的请求}).catch(error => console.error('Error:', error));}}function sendUpdate() {const newData = prompt('请输入要发送的数据:');fetch(`/update?data=${newData}`, { method: 'POST' }).then(response => response.text()).then(result => console.log(result)).catch(error => console.error('Error:', error));}// 初始调用pollServer();</script>
</body>
</html>

WebSocket 和长轮询的区别

特性WebSocket长轮询
连接类型持久连接短暂连接
通信方式全双工通信单向通信
延迟低延迟较高延迟
资源消耗相对较低相对较高
适用场景实时交互性强的应用,如聊天、游戏不支持WebSocket的老式浏览器
复杂度较高较低
兼容性需要浏览器和服务器的支持广泛支持

注意事项

WebSocket 注意事项
  1. 安全性:确保使用WSS(WebSocket Secure)协议进行加密通信。
  2. 心跳检测:定期发送心跳包以保持连接活跃,防止网络中断导致连接失效。
  3. 错误处理:处理连接失败、重连等异常情况。
  4. 负载均衡:在分布式环境中,确保WebSocket连接能够正确路由到正确的服务器实例。
长轮询 注意事项
  1. 超时设置:合理设置超时时间,避免过长时间的等待影响用户体验。
  2. 并发控制:限制同时发起的请求数量,避免服务器压力过大。
  3. 错误处理:处理请求失败、超时等情况,并提供重试机制。
  4. 性能优化:尽量减少不必要的请求次数,提高响应速度。

总结

  • WebSocket 提供了高效的全双工通信机制,适用于实时性要求高的应用场景,但实现相对复杂,需要考虑安全性和稳定性。
  • 长轮询 是一种简单有效的模拟服务器推送技术,适用于不支持WebSocket的老式浏览器或简单应用场景,但存在较高的延迟和资源消耗问题。

根据具体需求选择合适的技术方案,如果需要高效实时通信且支持现代浏览器,建议使用WebSocket;如果需要兼容性广且实现简单,可以选择长轮询。


http://www.ppmy.cn/server/175974.html

相关文章

告别数据库束缚!用esProc在 csv 文件上执行 SQL

esProc SPL 支持简单 SQL&#xff0c;可以直接在 csv 等结构化文本文件上执行 SQL 语句&#xff0c;这样&#xff0c;不用数据库也可以用 SQL 计算了。 先下载 esProc SPL&#xff1a;免费下载 不想折腾源代码的话&#xff0c;可以用标准版&#xff0c;找到相应版本下载后安装…

用 Vue 3.5 TypeScript 重新开发3年前甘特图的核心组件

回顾 3年前曾经用 Vue 2.0 开发了一个甘特图组件&#xff0c;如今3年过去了&#xff0c;计划使用Vue 3.5 TypeScript 把组件重新开发&#xff0c;有机会的话再开发一个React版本。 关于之前的组件以前文章 Vue 2.0 甘特图组件 下面录屏是是 用 Vue 3.5 TypeScript 开发的目前…

AGI大模型(8):提示词的安全与防护

1 前言 著名的「奶奶漏洞」&#xff0c;⽤套路把 AI 绕懵。 2 常⻅的提示词攻击技术 2.1 同类型⽬标劫持 同类⽬标劫持攻击&#xff0c;特别是在同类型任务的背景下&#xff0c;涉及到攻击者通过⾮法⼿段控制模型&#xff0c;并迫使其执行与原始任务性质相同但⽬标不同的操作…

Linux《进度条》

在之前的Linux基础开发工具当中我们已经了解了vim、gcc、makefile等基本的开发工具&#xff0c;那么有了这些开发工具我们就可以来实现我们Linux旅程当中的第一个程序——进度条。相信通过该项目的实现能让你对vim等开发工具更加的熟悉。一起加油吧&#xff01;&#xff01;&am…

时区转换工具

开发一个Python程序&#xff0c;将用户输入的北京日期时间转换为全球多个目标地区的对应时间&#xff0c;支持手动选择地区&#xff0c;并显示开始和结束两个时间段的转换结果 import pytz from datetime import datetime import pandas as pd from tabulate import tabulate …

Python 视频爬取教程

文章目录 前言基本原理环境准备Python安装选择Python开发环境安装必要库 示例 1&#xff1a;爬取简单直链视频示例 2&#xff1a;爬取基于 HTML5 的视频&#xff08;以某简单视频网站为例&#xff09; 前言 以下是一个较为完整的 Python 视频爬取教程&#xff0c;包含基本原理…

计算机基础:二进制基础13,十六进制与二进制的相互转换

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;计算机基础&#xff1a;二进制基础12&#xff0c;十进制数转换为…

EasyExcel动态拆分非固定列Excel表格

使用EasyExcel动态拆分非固定列Excel表格 在Excel数据解析场景中&#xff0c;​动态列结构拆分是典型挑战&#xff08;如供应链系统中不同品类的属性字段差异较大&#xff09;。传统基于POJO映射的方案无法应对列数量不固定的场景。本方案采用EasyExcel的动态模型解析和Map数据…