当前位置: 首页 > news >正文

WebSocket实现网站点赞通知

WebSocket 详解

什么是 WebSocket?

WebSocket 是一种在单个 TCP 连接上进行全双工通信的网络协议,实现了浏览器与服务器之间的实时双向通信

与 HTTP 的根本区别

HTTP(请求-响应模式)

客户端: 请求 → 服务器
客户端: ← 响应 服务器
(连接关闭)

WebSocket(全双工模式)

客户端: ↔ 服务器
客户端: ↔ 服务器  
客户端: ↔ 服务器
(持续连接,双向实时通信)

WebSocket 协议特点

1. 一次握手,持久连接

// 握手过程
客户端 → 服务器: HTTP Upgrade 请求
客户端 ← 服务器: HTTP 101 Switching Protocols
// 之后就是 WebSocket 协议通信

2. 极小的协议开销

// 建立连接后,数据帧头很小
// HTTP 每次请求都有完整的头部,WebSocket 只有 2-14 字节的帧头

3. 真正的实时性

  • 服务器可以主动推送 数据给客户端
  • 无需客户端轮询询问
  • 毫秒级延迟

WebSocket 核心技术原理

连接建立过程

// 1. 客户端发起握手
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13// 2. 服务器响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

数据帧格式

 0                   1                   2                   30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

Spring Boot 中的 WebSocket 实现

1. 依赖配置

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

2. 配置类

package com.panda.wiki.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

3. 端点类(注解方式)

package com.panda.wiki.websocket;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;@Component
@ServerEndpoint("/ws/{token}")
public class WebSocketServer {private static final Logger LOG = LoggerFactory.getLogger(WebSocketServer.class);  // 修正 Logger/*** 每个客户端一个token*/private String token = "";/*** 使用线程安全的 ConcurrentHashMap*/public static ConcurrentHashMap<String, Session> map = new ConcurrentHashMap<>();/*** 连接成功*/@OnOpen  // 修正注解大小写public void onOpen(Session session, @PathParam("token") String token) {  // 修正参数语法map.put(token, session);this.token = token;LOG.info("有新连接:token:{},session id:{},当前连接数:{}", token, session.getId(), map.size());  // 修正日志语法}/*** 连接关闭*/@OnClose  // 修正注解大小写public void onClose(Session session) {map.remove(this.token);LOG.info("连接关闭,token:{},session id:{},当前连接数:{}", this.token, session.getId(), map.size());  // 修正日志语法}/*** 收到消息*/@OnMessagepublic void onMessage(String message, Session session) { LOG.info("收到消息: {},内容: {}", token, message);  // 修正日志语法}/*** 连接错误*/@OnErrorpublic void onError(Session session, Throwable error) { LOG.error("发生错误", error); }/*** 群发消息*/public static void sendInfo(String message) {  // 改为静态方法for (String token : map.keySet()) {Session session = map.get(token);try {if (session.isOpen()) {  // 检查会话是否仍然打开session.getBasicRemote().sendText(message);LOG.info("推送消息: {}, 内容: {}", token, message);  // 修正日志文字} else {// 如果会话已关闭,从map中移除map.remove(token);}} catch (IOException e) {LOG.error("推送消息失败: {}, 内容: {}", token, message, e);  // 修正日志文字// 发送失败,从map中移除无效连接map.remove(token);}}}/*** 向指定用户发送消息*/public static void sendToUser(String token, String message) {Session session = map.get(token);if (session != null && session.isOpen()) {try {session.getBasicRemote().sendText(message);LOG.info("向用户 {} 发送消息: {}", token, message);} catch (IOException e) {LOG.error("向用户 {} 发送消息失败", token, e);map.remove(token);  // 移除无效连接}} else {LOG.warn("用户 {} 不在线或连接已关闭", token);if (session != null) {map.remove(token);  // 清理无效连接}}}/*** 获取当前在线连接数*/public static int getOnlineCount() {return map.size();}/*** 检查用户是否在线*/public static boolean isOnline(String token) {Session session = map.get(token);return session != null && session.isOpen();}
}
http://www.dtcms.com/a/499357.html

相关文章:

  • NotoSansCJK和SourceHanSansSC两款字体区别浅谈
  • 串口屏学习
  • Conda 环境激活失败或 PATH 优先级被主 Anaconda 覆盖
  • 什么建网站免费做网站代码审计哪个工具比较好
  • AI协同编程架构师:驾驭智能体社会的元语言创造者
  • 肇庆建网站服务腾讯建站平台官网
  • 聊聊 Unity(小白专享、C# 小程序 之 播放器)
  • [MLflow] CI/CD | 测试自动格式化工作流 | Ruff格式化器 | 预提交钩子配置
  • 数据结构——二十四、图(王道408)
  • C#获取钉钉平台考勤记录
  • Java JVM “调优” 面试清单(含超通俗生活案例与深度理解)
  • opencv gpu cuda python c++版本测试代码
  • 建设旅游门户网站安徽网站建设推荐 晨飞网络
  • 鸿蒙Next Wear Engine Kit:打造无缝连接的穿戴应用体验
  • 哪里有免费的网站推广软件网站源码上传完后怎么做
  • 快手测开面试题总结合并版(按分类标注序号+出现频率)
  • P1005 [NOIP 2007 提高组] 矩阵取数游戏
  • JAVA面试复习笔记(待完善)
  • 七、WEB APIs(二)
  • LLMs-from-scratch :多种字节对编码(BPE)对比
  • 济南哪里有网站建设公司网站类网站开发源代码
  • 做笔记的网站源码wordpress手机版论坛
  • 网站推广有哪些举措域名需要跟网站名称一致么
  • 具身神经-机器人通讯架构与实现系列
  • [GO]gin框架:ShouldBindJSON与其他常见绑定方法
  • KUKA库卡焊接机器人二氧化碳节气
  • 机器人、具身智能的起步——线性系统理论|【三】线性、因果与时不变
  • 服务器做php网站吗wordpress评论贴图
  • 网站建设与管理的心得怎样做音乐网站
  • 请例举 Android 中常用布局类型,并简述其用法以及排版效率