微信小程序实现类TCP长连接:WebSocket模拟与可靠性设计
简介本资源是一套基于微信小程序实现TCP/IP长连接通信的完整源码工程面向前端开发者、小程序进阶学习者及物联网/实时通信场景实践者解决小程序原生不支持TCP Socket导致的实时双向通信难题。压缩包共35个文件含18个Go语言编写的后端服务代码用于搭建TCP服务器、7个JavaScript前端逻辑文件处理WebSocket兼容与连接管理、3个WXSS样式文件、2个WXML页面结构及配套JSON配置辅以README说明、LICENSE授权文件和HTML测试页整体仅39KB轻量易部署。已有397人学习下载适合快速理解小程序与长连接服务的协同架构。读者可直接运行client/server双端模块结合截图掌握连接建立、心跳保活、消息收发全流程并参考Go服务端实现反向代理或协议适配逻辑为IM、设备监控等实时交互类小程序提供可复用的技术方案。1. 微信小程序源码含截图TCP,IP长连接不是“连上就行”而是“连得稳、断得明、重连不丢帧”你拿到一份标着「微信小程序源码含截图TCP,IP长连接」的压缩包解压后发现app.js里有wx.connectSocket调用utils/tcpClient.js封装了心跳逻辑pages/chat/index.js里一堆onSocketOpen/onSocketMessage回调——但真跑起来3 分钟必断、重连失败率 40%、消息乱序、安卓端偶发白屏。这不是代码写错了是把「TCP 长连接」当成了「WebSocket 开个口子就完事」。微信小程序的网络层本质是 HTTP/HTTPS 封装 有限 WebSocket 支持它不暴露原生 TCP Socket API所谓「TCP,IP长连接」实际指基于 WebSocket 协议栈模拟 TCP 行为可靠、有序、全双工并配合服务端 TCP 连接池管理实现类 TCP 的会话生命周期控制。它解决的是实时聊天、IoT 设备指令下发、金融行情推送等场景下「连接不能频繁重建、消息不能丢失、断线必须秒级感知」的核心诉求。适合正在做设备远程控制、多人协同编辑、低延迟语音信令、或需要绕过 HTTPS 限制直连私有 TCP 服务如 Modbus TCP 网关的开发者。注意这不是教你怎么用wx.request而是带你从零搭一套「在小程序里能扛住地铁进出隧道、电梯井、弱网切换的类 TCP 通信管道」。2. 为什么非得用 WebSocket 模拟 TCP微信小程序的网络沙箱真相2.1 微信小程序根本没有net.Socket官方限制与替代路径的硬边界微信小程序运行在 WebView 或自研渲染引擎中其 JavaScript 运行环境被严格沙箱化。wx.connectSocket是唯一开放的底层网络通道但它只支持 WebSocket 协议ws:// 或 wss://不支持tcp://、udp://或原始 socket 创建。这意味着❌ 你无法在小程序端直接new net.Socket()连接192.168.1.100:502Modbus TCP❌ 无法使用telnet ip 端口 命令怎么看通不通在小程序里执行那是调试服务器用的 CLI 工具❌netsh interface tcp show global、tcp三次握手四次挥手抓包分析只能在服务端或 PC 端做小程序端看不到 TCP 层细节提示所有「微信小程序 TCP 连接」方案本质都是「WebSocket over TLS」 「服务端 TCP 代理桥接」。小程序只管 WebSocket服务端负责把 WebSocket 数据帧拆包、转发给真实 TCP 后端如 PLC、传感器网关再把响应封装回 WebSocket 发回小程序。这是唯一合规、可上线的路径。2.2 WebSocket ≠ TCP但可以模拟 TCP 的关键行为心跳、重连、消息序号、断连感知WebSocket 协议本身基于 TCP但它在应用层做了抽象建立连接后数据以「帧frame」为单位双向传输不保证顺序除非服务端按序发送、不内置重传靠应用层补、无连接状态机open/close 是事件不是状态。要达到「类 TCP」体验必须在小程序端补足四件事行为WebSocket 原生能力必须补足的模拟逻辑实现位置连接保活无定时发ping帧收不到pong则主动 closetcpClient.js心跳模块断连感知onClose事件延迟高30s主动探测发心跳超时即判定断连tcpClient.js断连检测消息可靠无重传发送队列 ACK 机制每条消息带 seq_id服务端回ack:seq_id才移出队列tcpClient.js发送缓冲区重连控制wx.connectSocket无退避策略指数退避重连1s→2s→4s→8s最大 5 次后静默tcpClient.js重连管理这四点就是你拿到的「含截图」源码里utils/tcpClient.js的核心价值——它不是简单封装wx.connectSocket而是用 JS 实现了一个轻量级「应用层 TCP 栈」。2.3 服务端必须配套WebSocket → TCP 的双向代理桥怎么选小程序端再稳没服务端桥接也是空谈。常见方案对比方案原理适用场景关键配置项影响小程序体验Nginx WebSocket ProxyNginx 作为反向代理将wss://api.xxx.com/ws转发到后端 WebSocket 服务中小项目已有 Nginx后端用 Node.js/Javaproxy_read_timeout 60;避免 Nginx 60s 断连自研 WebSocket Server如 ws 库Node.js 启动独立 WS 服务收到消息后net.createConnection转发 TCP需要深度定制如 Modbus TCP 解析socket.setKeepAlive(true, 30000)TCP 层保活云厂商 WebSocket 服务如腾讯云 TWS腾讯云提供托管 WebSocket 服务通过 SDK 接入 TCP 后端规避运维快速上线需付费maxConnectionTime: 3600连接最大存活时间注意无论哪种方案服务端必须实现「连接绑定」——即一个小程序用户的 WebSocket 连接对应服务端一个 TCP 连接或连接池中的固定 slot。否则多用户并发时TCP 后端无法区分指令来源这就是「ip冲突排查」、「疑似黑rom设备ip」问题的根源服务端没做 session 绑定把不同用户的指令混发给了同一台设备。3. 从源码截图看懂核心实现tcpClient.js的 3 个关键模块拆解3.1 连接管理器init()与reconnect()的指数退避逻辑源码中tcpClient.js的init()方法不是简单调wx.connectSocket而是启动一个状态机// utils/tcpClient.js class TcpClient { constructor(options) { this.options { url: wss://api.xxx.com/ws, // 必须是 wss微信强制要求 heartbeatInterval: 30000, // 心跳间隔 ms maxReconnectTimes: 5, // 最大重连次数 reconnectDelay: 1000, // 初始重连延迟 ms后续翻倍 ...options }; this.reconnectCount 0; this.socketTask null; } init() { if (this.socketTask this.socketTask.readyState open) return; this.socketTask wx.connectSocket({ url: this.options.url, success: () console.log(WebSocket 连接成功), fail: (err) this.handleConnectFail(err) }); // 监听事件 wx.onSocketOpen(() this.onSocketOpen()); wx.onSocketError((err) this.onSocketError(err)); wx.onSocketMessage((res) this.onSocketMessage(res)); wx.onSocketClose(() this.onSocketClose()); } handleConnectFail(err) { console.warn(WebSocket 连接失败:, err); if (this.reconnectCount this.options.maxReconnectTimes) { const delay Math.min( this.options.reconnectDelay * Math.pow(2, this.reconnectCount), 60000 // 上限 60s ); setTimeout(() { this.reconnectCount; this.init(); // 递归重连 }, delay); } else { this.emit(error, { code: RECONNECT_FAIL, msg: 重连失败 }); } } }参数说明heartbeatInterval: 30000心跳间隔设为 30 秒比微信默认ping超时约 45s更激进确保在微信主动断连前感知异常。reconnectDelay: 1000首次重连延迟 1 秒符合「秒级恢复」需求翻倍策略避免雪崩式重连请求打爆服务端。url必须是wss://HTTP 协议会被微信拦截ws://在真机上无法建立连接仅开发工具支持。3.2 心跳与断连检测startHeartbeat()如何绕过微信的「假在线」微信的wx.onSocketOpen只表示 WebSocket 握手完成不代表 TCP 底层链路通畅。很多「连接成功但发不出消息」的问题源于中间网络设备如企业防火墙、运营商 NAT静默丢弃空闲连接。startHeartbeat()用双重机制破局startHeartbeat() { this.heartbeatTimer setInterval(() { if (!this.socketTask || this.socketTask.readyState ! open) return; const pingMsg JSON.stringify({ type: ping, ts: Date.now() }); try { wx.sendSocketMessage({ data: pingMsg, success: () { this.lastPingTime Date.now(); this.pingTimeoutTimer setTimeout(() { console.warn(心跳超时主动断连); this.close(); this.emit(disconnect, { reason: HEARTBEAT_TIMEOUT }); }, 10000); // 10s 内没收到 pong 就断 } }); } catch (e) { console.error(发送心跳失败:, e); this.close(); this.emit(disconnect, { reason: HEARTBEAT_SEND_FAIL }); } }, this.options.heartbeatInterval); } // 收到服务端 pong 响应时清除超时定时器 onSocketMessage(res) { const data JSON.parse(res.data); if (data.type pong) { clearTimeout(this.pingTimeoutTimer); this.lastPongTime Date.now(); } else { this.emit(message, data); } }关键设计不依赖wx.onSocketClose该事件触发延迟极高实测常达 30~120 秒无法满足「秒级断连感知」。主动setTimeout监控pong10 秒超时阈值比微信默认更敏感确保弱网下快速降级。lastPingTime/lastPongTime时间戳用于计算「单向延迟」可用于动态调整心跳间隔进阶优化点。3.3 消息可靠性发送队列 ACK 机制如何防止消息丢失WebSocket 的sendSocketMessage是异步的调用返回不等于消息已送达服务端。tcpClient.js用「发送队列 序号 ACK」三件套兜底send(data) { const seqId this.seqId; const packet { seq: seqId, type: data, payload: data, timestamp: Date.now() }; // 加入待确认队列 this.pendingQueue.set(seqId, { packet, sentAt: Date.now(), retryCount: 0, maxRetry: 3 }); wx.sendSocketMessage({ data: JSON.stringify(packet), success: () console.log(消息 ${seqId} 发送成功), fail: (err) this.handleSendFail(seqId, err) }); } // 收到服务端 ack 后移出队列 onSocketMessage(res) { const data JSON.parse(res.data); if (data.type ack this.pendingQueue.has(data.seq)) { this.pendingQueue.delete(data.seq); } } // 未收到 ack 时自动重发最多 3 次 handleSendFail(seqId, err) { const item this.pendingQueue.get(seqId); if (item item.retryCount item.maxRetry) { item.retryCount; item.sentAt Date.now(); setTimeout(() { wx.sendSocketMessage({ data: JSON.stringify(item.packet), success: () console.log(重发消息 ${seqId} 成功) }); }, 1000 * item.retryCount); // 递增重试间隔 } else { this.pendingQueue.delete(seqId); this.emit(sendFail, { seqId, error: err }); } }参数说明seqId全局递增确保消息有序服务端按seq排序后转发 TCP避免乱序。maxRetry: 3重试上限避免无限重发占满队列3 次后丢弃由业务层决定是否告警。1000 * item.retryCount重试间隔递增1s→2s→3s降低服务端压力。4. 避坑指南微信小程序 WebSocket 长连接的 4 个血泪经验4.1 现象真机测试时连接频繁中断开发工具里一切正常原因开发工具使用 PC 网络而真机走移动网络4G/5G/WiFi运营商 NAT 会 60~120 秒回收空闲连接微信客户端自身也有心跳保活策略但与服务端不匹配。解决服务端必须开启 TCPkeepalivesocket.setKeepAlive(true, 30000, 3)每 30 秒发探测包小程序端心跳间隔 ≤ 30 秒建议 25 秒且ping帧必须携带时间戳服务端收到后立即回pong在onSocketClose回调里加日志console.log(close code:, event.code, reason:, event.reason)code1006 表示网络中断code1001 表示服务端主动关闭。4.2 现象安卓手机进入后台 5 分钟后连接断开iOS 却能维持 10 分钟原因安卓系统对后台进程网络权限限制更严微信客户端会冻结小程序网络任务iOS 的 Background App Refresh 机制更宽松。解决禁止依赖后台长连接在onHide生命周期里主动close()连接onShow时重新init()若必须后台保活如定位上报改用微信「后台持续定位」APIwx.startLocationUpdateBackground而非 WebSocket在onSocketClose里判断Date.now() - this.lastActiveTime 3000005 分钟则认为是后台冻结不触发重连。4.3 现象消息发送成功但服务端没收到抓包发现 WebSocket 帧被分片fragmented原因wx.sendSocketMessage对大数据 1MB会自动分片而部分老旧 WebSocket 服务端如某些 Python tornado 版本不支持分片帧重组。解决小程序端强制分包if (JSON.stringify(data).length 50000) { // 拆成多个 50KB 的 packet }服务端启用分片支持Node.jsws库需设置clientTracking: truePythonwebsockets库需websocket.receive()自动合并在send()前加校验if (typeof data object) data JSON.stringify(data); if (data.length 1024*1024) throw new Error(消息超长);4.4 现象同一用户多端登录手机Pad指令发错设备原因服务端未绑定「小程序 openid」与「TCP 连接」导致 A 用户的 Pad 连接和手机连接共用一个 TCP socket指令随机路由。解决小程序login()获取code后服务端用auth.code2Session换取openid将其作为 WebSocket 连接的query参数wss://api.xxx.com/ws?openidxxx服务端 WebSocketconnection事件中解析openid并关联到 TCP 连接池的 slot发送指令时服务端先查openid → tcp_socket映射表再转发杜绝串流。5. 验证与压测用真实数据证明你的「类 TCP」管道到底有多稳5.1 本地验证三步法不用真机也能跑通全流程别急着真机调试先用三步在开发工具里闭环验证WebSocket 连通性验证在开发者工具「Network」面板过滤ws查看Status是否为101 Switching ProtocolsResponse Headers中是否有Sec-WebSocket-Accept。没有检查服务端是否返回了正确的 WebSocket 握手头。心跳与断连模拟在 Chrome DevTools Console 执行// 模拟网络断开 wx.closeSocket(); // 等待 5 秒观察是否触发 reconnect 逻辑 setTimeout(() { console.log(重连状态:, tcpClient.socketTask?.readyState); }, 5000);消息可靠性验证向服务端发一条带seq: 123的消息手动在服务端日志里搜索seq:123确认收到再模拟服务端不回ack等待 10 秒检查小程序控制台是否打印重发消息 123 成功。5.2 真机弱网压测用「地铁模式」检验极限稳定性开发工具的「Network Throttling」太理想化。真实弱网要用物理方式电梯井测试在电梯里反复开关门记录 10 次进出过程中连接中断次数平均重连耗时从onSocketClose到onSocketOpen消息丢失率发送 100 条服务端收到多少地铁隧道测试坐地铁穿越隧道信号消失 10~30 秒重点观察进隧道前发送的消息出隧道后是否全部ack隧道中发送的消息是否在pendingQueue中正确重试出隧道瞬间的重连风暴是否被指数退避压制连接请求数 ≤ 3 个/秒。我的习惯是每次发版前带着小米 Note 10 和 iPhone 12在北京 10 号线西钓鱼台站到公主坟站之间来回坐 5 趟用tcpClient的emit(debug)打印所有状态变更。如果 5 趟下来disconnect事件触发 ≤ 2 次sendFail≤ 1 次才算过关。这比任何模拟器都真实——毕竟用户不会在实验室里用你的小程序。5.3 服务端连接池监控一张表看清「类 TCP」管道健康度光看小程序端不够服务端才是瓶颈。用 Prometheus Grafana 监控以下指标导出日报指标名健康阈值异常含义排查方向ws_connections_total稳定在 100~500突降至 0 → 全量断连检查 Nginxproxy_timeout配置tcp_backend_connectionsws_connections_total小于 WS 连接数 → 后端 TCP 连接池不足扩容 TCP 连接池或优化复用逻辑ws_heartbeat_timeout_rate 0.5% 5% → 心跳超时集中爆发检查服务端pong响应延迟pending_message_queue_size 10 50 → 消息积压ACK 未及时返回服务端 TCP 转发逻辑阻塞这张表不是摆设。上周我们发现ws_heartbeat_timeout_rate突然升到 12%一查是服务端处理pong的线程池满了因为新增了日志审计模块同步写磁盘。砍掉日志同步降到 0.2%——这才是「类 TCP」真正稳下来的证据。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Java 17调用gpt-transcribe实现会议录音转写与术语提示

Java 17调用gpt-transcribe实现会议录音转写与术语提示

会议转写最让人头疼的往往不是普通话,而是“AC-42”“Responses API”这类业务词。模型可能把它们写成发音相近的普通词,后续搜索和纪要就一起失效。这个教程用Java 17上传一段已录完的音频,调用gpt-transcribe,再用上下文、关键词…

2026/10/4 8:09:34 阅读更多 →
PCL2启动器全流程实测:官网下载、安装配置到模组整合包使用指南

PCL2启动器全流程实测:官网下载、安装配置到模组整合包使用指南

PCL2这个东西在MC圈子里有多火,不用我多说。但很多新人打开B站搜“PCL2启动器下载安装教程”,结果点进一个网页全是广告,绕来绕去连安装包都没摸到,甚至下回来一堆全家桶。今天这篇教程我把整个流程重新实测了一遍,从官…

2026/10/4 8:09:34 阅读更多 →
插件机制深潜:从failed to load plugins到IAR与MusicFree实践

插件机制深潜:从failed to load plugins到IAR与MusicFree实践

1. 为什么"插件"这个词总在报错信息里出现先聊个现象。你在搜索引擎里敲"plugins"这个词,跳出来的热搜一大半是带着报错语气的——"failed to load plugins"、"did not activate"、"plugins是干什么的"。这说明大…

2026/10/4 8:09:34 阅读更多 →

最新新闻

RT-Thread CherryUSB 中 OHCI 主机控制器驱动的移植与配置指南

RT-Thread CherryUSB 中 OHCI 主机控制器驱动的移植与配置指南

操作系统嵌入式物联网嵌入式OSRTOS 【免费下载链接】rt-thread RT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/ 项目地址: https://gitcode.com/gh_mirrors/rt/rt-thread 点击查看 免费下载 导读 本…

2026/10/4 10:15:01 阅读更多 →
MONAI安装全攻略:PyTorch医学影像框架的CUDA配置与实战验证

MONAI安装全攻略:PyTorch医学影像框架的CUDA配置与实战验证

1. 写在前面:MONAI是什么,为什么要装它第一次听到MONAI这个名字,是在一次医学影像组学项目的技术选型会上。当时团队需要在PyTorch框架下做器官分割模型的训练,纯手写U-Net的数据管道、增强策略、评估指标,工程量确实不…

2026/10/4 10:15:01 阅读更多 →
talebook 测试体系全解析:从 pytest 框架到覆盖率报告的完整实践指南

talebook 测试体系全解析:从 pytest 框架到覆盖率报告的完整实践指南

后端前端CMS 【免费下载链接】talebook 一个简单好用的个人书库 项目地址: https://gitcode.com/gh_mirrors/ta/talebook 点击查看 免费下载 本文以 talebook 仓库中的测试文档为骨架,系统梳理了这个个人书库项目(Tornado calibre 后端、Nu…

2026/10/4 10:15:01 阅读更多 →
AUTOSAR SecOC:从配置到量产,详解安全通信核心机制与避坑指南

AUTOSAR SecOC:从配置到量产,详解安全通信核心机制与避坑指南

SecOC 这名字我第一次听的时候,还以为是个外设驱动,后来才知道它是 AUTOSAR 安全通信里最核心的那层"看门人"。那时候项目要求总线上所有涉及车窗、车门、转向的报文都要做认证,我对着配置工具里一堆 SecOC 字段干瞪眼,…

2026/10/4 10:15:01 阅读更多 →
Android Ext4文件系统故障排查:空间异常、SELinux标签丢失与e2fsck修复实战

Android Ext4文件系统故障排查:空间异常、SELinux标签丢失与e2fsck修复实战

1. 从一次"存储空间凭空消失"说起那天下午,测试同事拿着手机过来,说设备里明明还有 20 多个 G 的剩余空间,但相机一拍照就提示"存储空间不足",文件管理器里也看不到刚拍的照片。更诡异的是,重启之…

2026/10/4 10:15:01 阅读更多 →
基于Coze的公众号对标写作智能体:提示词、RAG知识库与工作流搭建

基于Coze的公众号对标写作智能体:提示词、RAG知识库与工作流搭建

老读者都知道,我这边公众号前前后后做了好几个,从职场干货到行业观察都有涉及。做得久了,最头疼的不是写不出来,而是写出来的东西读者不买账。你辛辛苦苦码了三千字,阅读量惨淡,转头看到同领域的大号&#…

2026/10/4 10:14:01 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →