[netty5: WebSocketProtocolHandler]-源码分析

在阅读这篇文章前,推荐先阅读:[netty5: MessageToMessageCodec & MessageToMessageEncoder & MessageToMessageDecoder]-源码分析

WebSocketProtocolHandler

WebSocketProtocolHandler 是 WebSocket 处理的基础抽象类,负责管理 WebSocket 帧的解码、关闭流程及通用协议逻辑。

abstract class WebSocketProtocolHandler extends MessageToMessageDecoder<WebSocketFrame> {private final boolean dropPongFrames;private final WebSocketCloseStatus closeStatus;private final long forceCloseTimeoutMillis;private Promise<Void> closeSent;WebSocketProtocolHandler() {this(true);}WebSocketProtocolHandler(boolean dropPongFrames) {this(dropPongFrames, null, 0L);}WebSocketProtocolHandler(boolean dropPongFrames, WebSocketCloseStatus closeStatus, long forceCloseTimeoutMillis) {this.dropPongFrames = dropPongFrames;this.closeStatus = closeStatus;this.forceCloseTimeoutMillis = forceCloseTimeoutMillis;}@Overrideprotected void decode(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {throw new UnsupportedOperationException("WebSocketProtocolHandler use decodeAndClose().");}@Overrideprotected void decodeAndClose(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {if (frame instanceof PingWebSocketFrame) {try (frame) {ctx.writeAndFlush(new PongWebSocketFrame(frame.binaryData().send()));}readIfNeeded(ctx);return;}if (frame instanceof PongWebSocketFrame && dropPongFrames) {frame.close();readIfNeeded(ctx);return;}ctx.fireChannelRead(frame);}private static void readIfNeeded(ChannelHandlerContext ctx) {if (!ctx.channel().getOption(ChannelOption.AUTO_READ)) {ctx.read();}}@Overridepublic Future<Void> close(final ChannelHandlerContext ctx) {if (closeStatus == null || !ctx.channel().isActive()) {return ctx.close();}final Future<Void> future = closeSent == null ?write(ctx, new CloseWebSocketFrame(ctx.bufferAllocator(), closeStatus)) : closeSent.asFuture();flush(ctx);applyCloseSentTimeout(ctx);Promise<Void> promise = ctx.newPromise();future.addListener(f -> ctx.close().cascadeTo(promise));return promise.asFuture();}@Overridepublic Future<Void> write(final ChannelHandlerContext ctx, Object msg) {if (closeSent != null) {Resource.dispose(msg);return ctx.newFailedFuture(new ClosedChannelException());}if (msg instanceof CloseWebSocketFrame) {Promise<Void> promise = ctx.newPromise();closeSent(promise);ctx.write(msg).cascadeTo(closeSent);return promise.asFuture();}return ctx.write(msg);}void closeSent(Promise<Void> promise) {closeSent = promise;}private void applyCloseSentTimeout(ChannelHandlerContext ctx) {if (closeSent.isDone() || forceCloseTimeoutMillis < 0) {return;}Future<?> timeoutTask = ctx.executor().schedule(() -> {if (!closeSent.isDone()) {closeSent.tryFailure(buildHandshakeException("send close frame timed out"));}}, forceCloseTimeoutMillis, TimeUnit.MILLISECONDS);closeSent.asFuture().addListener(future -> timeoutTask.cancel());}protected WebSocketHandshakeException buildHandshakeException(String message) {return new WebSocketHandshakeException(message);}@Overridepublic void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.fireChannelExceptionCaught(cause);ctx.close();}
}

WebSocketServerProtocolHandler

WebSocketServerProtocolHandler 负责在服务器端管理 WebSocket 握手、帧的解码与关闭处理,并支持协议校验与异常处理。

public class WebSocketServerProtocolHandler extends WebSocketProtocolHandler {private static final AttributeKey<WebSocketServerHandshaker> HANDSHAKER_ATTR_KEY = AttributeKey.valueOf(WebSocketServerHandshaker.class, "HANDSHAKER");private final WebSocketServerProtocolConfig serverConfig;public WebSocketServerProtocolHandler(WebSocketServerProtocolConfig serverConfig) {super(Objects.requireNonNull(serverConfig, "serverConfig").dropPongFrames(),serverConfig.sendCloseFrame(),serverConfig.forceCloseTimeoutMillis());this.serverConfig = serverConfig;}// `handlerAdded` 方法负责在 ChannelPipeline 中动态添加握手处理器和 UTF-8 校验器,确保 WebSocket 握手和数据帧合法性校验功能生效。@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {ChannelPipeline cp = ctx.pipeline();if (cp.get(WebSocketServerProtocolHandshakeHandler.class) == null) {// Add the WebSocketHandshakeHandler before this one.cp.addBefore(ctx.name(), WebSocketServerProtocolHandshakeHandler.class.getName(),new WebSocketServerProtocolHandshakeHandler(serverConfig));}if (serverConfig.decoderConfig().withUTF8Validator() && cp.get(Utf8FrameValidator.class) == null) {// Add the UFT8 checking before this one.cp.addBefore(ctx.name(), Utf8FrameValidator.class.getName(),new Utf8FrameValidator(serverConfig.decoderConfig().closeOnProtocolViolation()));}}@Overrideprotected void decodeAndClose(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {// 当收到关闭帧时,优先通过已绑定的 WebSocketServerHandshaker 进行优雅关闭,否则直接关闭连接;非关闭帧则继续正常处理。if (serverConfig.handleCloseFrames() && frame instanceof CloseWebSocketFrame) {WebSocketServerHandshaker handshaker = getHandshaker(ctx.channel());if (handshaker != null) {Promise<Void> promise = ctx.newPromise();closeSent(promise);handshaker.close(ctx, (CloseWebSocketFrame) frame).cascadeTo(promise);} else {frame.close();ctx.writeAndFlush(ctx.bufferAllocator().allocate(0)).addListener(ctx, ChannelFutureListeners.CLOSE);}return;}super.decodeAndClose(ctx, frame);}@Overrideprotected WebSocketServerHandshakeException buildHandshakeException(String message) {return new WebSocketServerHandshakeException(message);}@Overridepublic void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {if (cause instanceof WebSocketHandshakeException) {final byte[] bytes = cause.getMessage().getBytes();FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST,ctx.bufferAllocator().allocate(bytes.length).writeBytes(bytes));ctx.channel().writeAndFlush(response).addListener(ctx, ChannelFutureListeners.CLOSE);} else {ctx.fireChannelExceptionCaught(cause);ctx.close();}}static WebSocketServerHandshaker getHandshaker(Channel channel) {return channel.attr(HANDSHAKER_ATTR_KEY).get();}static void setHandshaker(Channel channel, WebSocketServerHandshaker handshaker) {channel.attr(HANDSHAKER_ATTR_KEY).set(handshaker);}
}

WebSocketClientProtocolHandler

WebSocketClientProtocolHandler 是 Netty 中用于处理 WebSocket 客户端协议升级、帧处理与自动注入握手与 UTF-8 校验器的核心 ChannelHandler。

public class WebSocketClientProtocolHandler extends WebSocketProtocolHandler {private final WebSocketClientHandshaker handshaker;private final WebSocketClientProtocolConfig clientConfig;public WebSocketClientHandshaker handshaker() {return handshaker;}public WebSocketClientProtocolHandler(WebSocketClientProtocolConfig clientConfig) {super(Objects.requireNonNull(clientConfig, "clientConfig").dropPongFrames(),clientConfig.sendCloseFrame(), clientConfig.forceCloseTimeoutMillis());this.handshaker = WebSocketClientHandshakerFactory.newHandshaker(clientConfig.webSocketUri(),clientConfig.version(),clientConfig.subprotocol(),clientConfig.allowExtensions(),clientConfig.customHeaders(),clientConfig.maxFramePayloadLength(),clientConfig.performMasking(),clientConfig.allowMaskMismatch(),clientConfig.forceCloseTimeoutMillis(),clientConfig.absoluteUpgradeUrl(),clientConfig.generateOriginHeader());this.clientConfig = clientConfig;}@Overrideprotected void decodeAndClose(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {if (clientConfig.handleCloseFrames() && frame instanceof CloseWebSocketFrame) {Resource.dispose(frame);ctx.close();return;}super.decodeAndClose(ctx, frame);}@Overrideprotected WebSocketClientHandshakeException buildHandshakeException(String message) {return new WebSocketClientHandshakeException(message);}// `handlerAdded` 方法会在当前 Handler 加入 pipeline 时,// 自动向其前方插入握手处理器和(可选的)UTF-8 校验器,以确保 WebSocket 客户端协议的正确初始化与安全性。@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {ChannelPipeline cp = ctx.pipeline();if (cp.get(WebSocketClientProtocolHandshakeHandler.class) == null) {// Add the WebSocketClientProtocolHandshakeHandler before this one.ctx.pipeline().addBefore(ctx.name(), WebSocketClientProtocolHandshakeHandler.class.getName(),new WebSocketClientProtocolHandshakeHandler(handshaker, clientConfig.handshakeTimeoutMillis()));}if (clientConfig.withUTF8Validator() && cp.get(Utf8FrameValidator.class) == null) {// Add the UFT8 checking before this one.ctx.pipeline().addBefore(ctx.name(), Utf8FrameValidator.class.getName(),new Utf8FrameValidator());}}
}

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

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

相关文章

[2025CVPR]一种新颖的视觉与记忆双适配器(Visual and Memory Dual Adapter, VMDA)

引言 多模态目标跟踪&#xff08;Multi-modal Object Tracking&#xff09;旨在通过结合RGB模态与其他辅助模态&#xff08;如热红外、深度、事件数据&#xff09;来增强可见光传感器的感知能力&#xff0c;尤其在复杂场景下显著提升跟踪鲁棒性。然而&#xff0c;现有方法在频…

理想汽车6月交付36279辆 第二季度共交付111074辆

理想汽车-W(02015)发布公告&#xff0c;2025年6月&#xff0c;理想汽车交付新车36279辆&#xff0c;第二季度共交付111074辆。截至2025年6月30日&#xff0c;理想汽车历史累计交付量为133.78万辆。 在成立十周年之际&#xff0c;理想汽车已连续两年成为人民币20万元以上中高端市…

MobileNets: 高效的卷积神经网络用于移动视觉应用

摘要 我们提出了一类高效的模型&#xff0c;称为MobileNets&#xff0c;专门用于移动和嵌入式视觉应用。MobileNets基于一种简化的架构&#xff0c;利用深度可分离卷积构建轻量级的深度神经网络。我们引入了两个简单的全局超参数&#xff0c;能够有效地在延迟和准确性之间进行…

SDP服务发现协议:动态查询设备能力的底层逻辑(面试深度解析)

SDP的底层逻辑揭示了物联网设备交互的本质——先建立认知,再开展协作。 一、SDP 核心知识点高频考点解析 1.1 SDP 的定位与作用 考点:SDP 在蓝牙协议栈中的位置及核心功能 解析:SDP(Service Discovery Protocol,服务发现协议)位于蓝牙协议栈的中间层,依赖 L2CAP 协议传…

CppCon 2018 学习:GIT, CMAKE, CONAN

提到的&#xff1a; “THE MOST COMMON C TOOLSET” VERSION CONTROL SYSTEM BUILDING PACKAGE MANAGEMENT 这些是 C 项目开发中最核心的工具链组成部分。下面我将逐一解释每部分的作用、常见工具&#xff0c;以及它们如何协同构建现代 C 项目。 1. VERSION CONTROL SYSTEM&am…

使用tensorflow的线性回归的例子(五)

我们使用Iris数据&#xff0c;Sepal length为y值而Petal width为x值。import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph()# Load the data# iris.d…

虚幻基础:动作——蒙太奇

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 动作——蒙太奇如果动作被打断&#xff0c;则后续的动画通知不会执行 动作——蒙太奇 如果动作被打断&#xff0c;则后续的动画通知不会执行

[工具系列] 开源的 API 调试工具 Postwoman

介绍 随着 Web 应用的复杂性增加&#xff0c;API 测试已成为开发中不可或缺的一部分&#xff0c;无论是前端还是后端开发&#xff0c;确保 API 正常运行至关重要。 Postman 长期以来是开发者进行 API 测试的首选工具&#xff0c;但是很多基本功能都需要登陆才能使用&#xff…

【力扣 简单 C】746. 使用最小花费爬楼梯

目录 题目 解法一 题目 解法一 int min(int a, int b) {return a < b ? a : b; }int minCostClimbingStairs(int* cost, int costSize) {const int n costSize; // 楼顶&#xff0c;第n阶// 爬到第n阶的最小花费 // 爬到第n-1阶的最小花费从第n-1阶爬上第n阶的花费…

python+django开发带auth接口

pythondjango开发带auth接口 # coding utf-8 import base64 from django.contrib import auth as django_authfrom django.core.exceptions import ObjectDoesNotExist from django.http import JsonResponsefrom sign.models import Eventdef user_auth(request):"&quo…

RBAC权限模型如何让API访问控制既安全又灵活?

url: /posts/9f01e838545ae8d34016c759ef461423/ title: RBAC权限模型如何让API访问控制既安全又灵活? date: 2025-07-01T04:52:07+08:00 lastmod: 2025-07-01T04:52:07+08:00 author: cmdragon summary: RBAC权限模型通过用户、角色和权限的关联实现访问控制,核心组件包括用…

安达发|告别低效排产:APS高级排程如何助力电池企业智造升级?

在全球能源转型的背景下&#xff0c;动力电池、储能电池等市场需求快速增长&#xff0c;电池制造企业面临着订单波动大、工艺复杂、交期严格等挑战。传统的手工排产或基于ERP的简单计划模式已难以满足高效、精准的生产需求。APS高级排程通过智能算法优化生产计划&#xff0c;实…

数据结构20250620_数据结构考试

试卷01 天津金海通软件笔试题 选择题(4*416) 对于双向循环链表,在p指针所指的结点之后插入s指针所指结点的操作应为 p->nexts; s->prip; p->next->pris; s->nextp->nextp->nexts; p->next->pris; s->prip; s->nextp->nexts->pri …

4. 寻找正序数组的中位数

题目&#xff1a; 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为 O(log (mn)) 。 示例&#xff1a; 输入&#xff1a;nums1 [1,3], nums2 [2] 输出&#xff1a…

DeepSeek飞机大战小游戏HTML5(附源码)

用DeepSeek帮忙生成的飞机大战小游戏网页版&#xff0c;基于HTML5。 提示词prompt 帮我做一个网页版的飞机大战游戏 html5的游戏功能说明 玩家控制&#xff1a; 使用键盘方向键或WASD移动飞机 空格键发射子弹 移动设备支持触摸控制 游戏机制&#xff1a; 敌机会从屏幕顶部随机位…

全素山药开发指南:从防痒处理到高可用食谱架构

摘要&#xff1a;本文系统性解析山药的化学特性&#xff08;黏液蛋白/皂苷致痒机制&#xff09;及全素场景下的烹饪解决方案&#xff0c;提供6种高内聚低耦合的食谱实现&#xff0c;附完整防氧化与黏液控制技术方案。一、核心问题分析&#xff1a;山药处理中的“痛点”致痒物质…

OpenLayers 入门指南:序言

本专栏旨在帮助零GIS基础的开发人员系统掌握OpenLayers这一强大的开源Web地图库&#xff0c;通过 “理论实战” 结合的方式&#xff0c;逐步实现从创建地图到构建一个基础地图应用模版。无论你是前端开发者、GIS爱好者&#xff0c;都可以通过此专栏零基础开始用OpenLayers开发一…

WebRTC轻量学习 libdatachannel

最近想了解一些在浏览器中推送音视频流&#xff0c;寻找很多版本的代码&#xff0c;C、Go、Python等语言实现的webRTC协议。 按照搭建难度和快速实现首选Python版本的WebRTC&#xff0c;这种是最适合原型开发的。 选型&#xff1a;C的开源库libdatachannel Python的开源库Ai…

Vue2中的keep-alive:组件状态缓存与性能优化实战指南

目录 一、什么是keep-alive&#xff1f; 与普通组件切换的对比 二、核心用法详解 1. 基础用法&#xff1a;动态组件缓存 2. 路由视图缓存 3. 生命周期钩子 三、进阶配置与优化 1. 精准控制缓存组件 &#xff08;1&#xff09;include/exclude属性 &#xff08;2&…

FastAPI安全加固:密钥轮换、限流策略与安全头部如何实现三重防护?

url: /posts/f96ba438de34dc197fd2598f91ae133d/ title: FastAPI安全加固:密钥轮换、限流策略与安全头部如何实现三重防护? date: 2025-07-02T22:05:04+08:00 lastmod: 2025-07-02T22:05:04+08:00 author: cmdragon summary: FastAPI框架安全加固方案包括密钥轮换自动化、请…