Flash游戏服务器为何偏爱select模型而非epoll
简介本资源是一套基于TCP协议与select I/O多路复用模型实现的Flash网络游戏通信实践案例面向网络编程初学者及C服务端开发入门者聚焦于客户端SWF游戏与控制台服务器之间的实时交互机制。压缩包共15个文件含2个核心源码文件cpp/h、2个编译产物obj/pdb、1个可执行程序exe及配套工程文件dsw/dsp、调试支持文件ilk/idb/pch和说明文档txt完整呈现VC6.0环境下从编码、编译到运行的全流程。资源包大小649KB轻量易解压适合作为课堂实验或自学项目快速上手。已有235人学习下载读者可直接运行flash_car.exe服务器结合flash_car2.swf客户端理解TCP连接建立、select模型轮询监听、自定义数据包格式解析等关键实现并通过PPT深入掌握游戏状态同步的设计逻辑与通信约定。1. Flash游戏服务器为什么用 select 模型写 TCP 连接管理反而比 epoll 更稳你可能已经删掉了本地所有 Flash 游戏的 .swf 文件但如果你翻过某跨平台系统早期的联机对战模块、某高校实验室的实时交互 Demo、或某图像处理 Demo 的配套服务端代码大概率会撞见一个反直觉的事实在 2015–2018 年间大量上线的 Flash 多人游戏服务器并没有急着上 epoll 或 kqueue而是坚持用最“古老”的select模型实现 TCP 连接管理——不是因为不会而是因为在那个特定负载场景下select 的确定性行为、低内存开销和可预测的阻塞点恰恰成了稳定性的压舱石。这不是技术怀旧而是一次精准的工程取舍Flash 客户端连接数通常在 200–800 之间心跳间隔固定30s消息体小 2KB且绝大多数连接长期空闲此时select的 O(n) 轮询开销几乎为零而 epoll 的红黑树就绪链表带来的额外 cache miss 和内核态/用户态切换成本在低并发、高闲置率场景下反而成了负优化。更关键的是select的超时参数让心跳检测、连接清理、协议解析错误恢复等逻辑全部收束在一个统一的FD_SET循环里调试时能一眼看清“此刻哪些 socket 在读、哪些在写、哪些已断开”——这种白盒可控性在 Flash 时代频繁出现的客户端闪退、TCP 半开连接、Flash Player 自身 socket 状态错乱等玄学问题面前就是最好的后悔药。2. select 模型的本质不是轮询而是「状态快照 时间切片」的协同机制2.1 select 不是“每轮扫一遍 fd”而是「一次系统调用完成三类状态捕获」很多开发者误以为select()是个低效的轮询函数其实它在内核层面干的是三件事注册监听集合把传入的readfds/writefds/exceptfds三个 fd_set 拷贝进内核标记哪些 socket 需要关注读就绪、写就绪或异常挂起并等待进程进入可中断睡眠TASK_INTERRUPTIBLE内核只在这些被标记的 socket 上发生对应事件时才唤醒它返回快照唤醒后内核把当前时刻“哪些 socket 确实就绪了”这个结果原路写回用户传入的 fd_set 中注意是修改原结构体不是返回新结构。这意味着select()的时间复杂度瓶颈不在“扫描”而在每次调用都要拷贝 fd_set 进出内核。fd_set 默认大小是 1024FD_SETSIZE每个 bit 代表一个 fd 是否被监听所以拷贝开销是固定的1024/8 128 字节—— 无论你实际只监听 3 个 socket 还是 1000 个。这解释了为什么它适合中低并发当连接数 500 时拷贝成本远低于 epoll_ctl() 维护红黑树节点的指针操作内存分配。// 典型 Flash 服务器中的 select 主循环节选简化 fd_set read_fds, write_fds; struct timeval timeout { .tv_sec 1, .tv_usec 0 }; // 1秒超时用于心跳驱动 while (running) { FD_ZERO(read_fds); FD_ZERO(write_fds); // 将所有活跃 socket 加入 read_fds含 listen_fd for (int i 0; i max_fd; i) { if (clients[i].state CLIENT_ACTIVE) { FD_SET(i, read_fds); if (clients[i].has_data_to_send) { FD_SET(i, write_fds); } } } int ret select(max_fd 1, read_fds, write_fds, NULL, timeout); if (ret 0) { if (errno EINTR) continue; // 被信号中断重试 perror(select failed); break; } // 此时 read_fds/write_fds 已被内核修改只保留就绪的 fd handle_new_connection_if_needed(read_fds); // 检查 listen_fd handle_client_reads(read_fds); // 遍历所有被置位的 fd 做 recv() handle_client_writes(write_fds); // 遍历所有被置位的 fd 做 send() check_heartbeats_and_timeout(); // 超时逻辑在此统一触发 }提示这段代码里max_fd 1是select()第一个参数它不是连接数而是当前所有被监听 fd 中的最大值加 1。如果listen_fd3某个 client fd999那这里必须传1000。漏传会导致select()忽略高位 fd —— 这是 Flash 服务器早期最隐蔽的连接丢失 bug 来源之一。2.2 为什么 Flash 场景下 select 的「超时驱动」比「事件驱动」更可靠Flash Player 的网络栈在 AS3 时代存在一个硬伤XMLSocket和Socket类在底层关闭连接时不保证发送 FIN 包。常见现象是客户端页面关闭后socket 还维持在ESTABLISHED状态但后续任何send()都会失败而recv()则永远阻塞或返回 0取决于是否启用了SO_KEEPALIVE。epoll 在这种半开连接下会持续报告EPOLLIN因为 TCP 缓冲区空recv()返回 0 被视为“可读”导致服务器不断尝试读取陷入假活跃状态。而select()的timeval参数天然提供了「时间切片」能力只要设置合理超时如 1 秒主循环每秒必醒一次。此时我们可以在check_heartbeats_and_timeout()中做两件事对每个 client 记录最后收到数据的时间戳超时如 45s则强制 close对每个 client 检查send()返回值若为 -1 且errno EAGAIN/EWOULDBLOCK说明内核发送缓冲区满但连接仍健康若为 -1 且errno EPIPE/ECONNRESET说明对端已崩立即清理。这种「定时巡检 状态快照」的组合把网络不可靠性转化成了可编程的超时逻辑比依赖内核事件更可控。2.3 fd_set 的位图结构如何影响内存布局与缓存友好性fd_set在 glibc 中定义为#define __FD_SETSIZE 1024 typedef struct { __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS]; } __fd_set_t;其中__NFDBITS通常是8 * sizeof(__fd_mask)64 位系统为 64所以__fds_bits是一个长度为1024/64 16的unsigned long数组。整个结构体大小固定为128 字节能放进 CPU 一级缓存L1d cache line 通常 64 字节但现代 CPU 多用 128 字节预取。这意味着每次select()调用内核只需拷贝 128 字节进出用户态遍历FD_ISSET(i, read_fds)本质是((fd_set-__fds_bits[i/64] (i%64)) 1)纯位运算无分支预测失败当 Flash 服务器实际连接数仅 300 时__fds_bits[0..4]被频繁访问其余 11 个元素几乎不命中 —— L1 缓存污染极小。对比 epollepoll_wait()返回的是就绪事件数组每个epoll_event至少 12 字节events data且内核需动态维护红黑树节点每个节点约 40 字节在连接数 500 时select的 cache locality 明显更优。3. Flash 协议层与 select 的耦合设计为什么不能直接套用通用 TCP 服务器模板3.1 Flash 的 AMF0/AMF3 协议要求「单 socket 全双工复用」而非 HTTP 式请求响应Flash 游戏通信不走 HTTP而是用 Action Message FormatAMF序列化二进制消息。一个典型交互流程是客户端连上服务器后先发connect命令AMF0 编码服务器返回onStatus响应含NetConnection.Connect.Success后续所有游戏逻辑移动、攻击、聊天都通过同一 socket 的call命令发送服务器用result或onStatus异步返回。这带来两个硬约束必须支持读写分离connect请求很小 100B但call可能带图片 Base641MB服务器需在read_fds就绪时优先收完整包AMF 有明确 length header在write_fds就绪时才发响应否则会因 TCP 粘包或发送缓冲区满导致协议错乱必须容忍非对称吞吐客户端可能连续发 5 个call但服务器只回 2 个result其余由广播触发write_fds就绪频率远低于read_fds。因此Flash 服务器的select循环必须严格区分读写路径// handle_client_reads() 中的关键逻辑 for (int fd 0; fd max_fd; fd) { if (!FD_ISSET(fd, read_fds)) continue; if (fd listen_fd) { accept_new_client(); // 新连接加入 clients[] 并置位 continue; } // 对已有 client先检查是否需要收包头4字节 length if (clients[fd].state READING_HEADER) { ssize_t n recv(fd, clients[fd].header_buf, 4 - clients[fd].header_received, 0); if (n 0) { clients[fd].header_received n; if (clients[fd].header_received 4) { clients[fd].expected_body_len ntohl(*(uint32_t*)clients[fd].header_buf); clients[fd].state READING_BODY; } } } // 再检查是否需要收包体 else if (clients[fd].state READING_BODY) { ssize_t n recv(fd, clients[fd].body_buf clients[fd].body_received, clients[fd].expected_body_len - clients[fd].body_received, 0); if (n 0) { clients[fd].body_received n; if (clients[fd].body_received clients[fd].expected_body_len) { parse_amf_message(clients[fd].body_buf, clients[fd].expected_body_len); clients[fd].state READING_HEADER; // 重置 clients[fd].header_received 0; } } } }注意这里recv()必须用MSG_WAITALL吗不能。AMF 包体可能跨 TCP segmentMSG_WAITALL会阻塞到整包到达而select()已经保证了 socket 可读 —— 但可读不等于“有足够数据”。所以必须用非阻塞recv() 状态机这是 Flash 服务器区别于 HTTP 服务器的核心编码范式。3.2 心跳与连接保活必须绕过 AMF 协议栈走裸 TCP 层Flash Player 的XMLSocket不支持自定义心跳帧Socket类虽可发任意二进制但若在 AMF 包里塞心跳字段服务器解析时会因类型不符报错。真实方案是服务器主动发裸字节0x00作为心跳客户端收到后必须原样回0x00。这个0x00不经过 AMF 解析器直接由 socket 层处理。这就要求select循环中check_heartbeats_and_timeout()每 30 秒遍历所有 client对last_recv_time超过 25 秒的 fd调用send(fd, \x00, 1, MSG_DONTWAIT)handle_client_reads()收到0x00时不走 AMF 解析直接更新last_recv_time并丢弃若recv()返回 0对端关闭或send()返回EPIPE立即清理 client。这种协议外的心跳让select的超时机制成为唯一可信的保活依据 —— epoll 的EPOLLET边沿触发反而会漏掉0x00这种瞬时事件。3.3 客户端闪退导致的「TIME_WAIT 雪崩」如何用 select 的连接池缓解Flash 页面关闭时浏览器不保证调用socket.close()大量连接会卡在TIME_WAIT状态Linux 默认 60 秒。当服务器每秒接受 50 个新连接60 秒内就会积压 3000 个TIME_WAITsocket耗尽本地端口65535 个。通用解法是net.ipv4.tcp_tw_reuse1但 Flash 服务器采用更激进的策略复用 client 结构体而非 fd。在clients[]数组中每个 slot 存储fd当前 socket fd为 -1 表示空闲stateCLIENT_IDLE/CLIENT_ACTIVE/CLIENT_CLOSINGlast_recv_time用于心跳send_queue待发送的 AMF 包链表。当accept()成功找第一个fd -1的 slotdup2()新 fd 到该 slot 的 fd 位置当连接断开不close(fd)而是设fd -1清空状态留待复用。这样TIME_WAIT仍存在但只占fd不占clients[]slotselect()的max_fd不会无限增长上限为clients[]长度FD_SET(fd, read_fds)时fd总是有效值避免select()因无效 fd 报错。这是select模型特有的资源控制技巧 —— epoll 的epoll_ctl(EPOLL_CTL_ADD)要求 fd 必须有效无法做这种“预分配 slot”。4. 常见问题排查那些让 Flash 服务器半夜告警的 select 血泪经验4.1 现象客户端能连上但发第一条connect命令后无响应strace显示select()永远不返回原因listen_fd未加入read_fds。select()只监听你显式FD_SET()的 fdlisten_fd不在集合中新连接到达时内核不会唤醒进程。解决确保FD_SET(listen_fd, read_fds)在每次select()调用前执行且listen_fd小于max_fd 1。4.2 现象服务器运行 2 小时后部分客户端卡死netstat显示连接处于ESTABLISHED但无数据交换原因check_heartbeats_and_timeout()中未正确处理send()返回EAGAIN。当内核发送缓冲区满send()返回 -1 errnoEAGAIN但代码误判为连接错误提前close(fd)导致客户端收不到心跳响应而超时。解决send()后必须检查errno仅当EPIPE/ECONNRESET/ECONNABORTED才清理连接EAGAIN应保持client.state CLIENT_SENDING并在下次write_fds就绪时重试。4.3 现象select()返回ret0超时但FD_ISSET()检查所有 fd 都为 false心跳逻辑失效原因timeval结构体未初始化。struct timeval timeout {0}未显式赋值tv_sec和tv_usec可能为随机值导致select()实际超时时间极短如 0.0001 秒或极长如 2^32 秒。解决必须显式初始化timeout.tv_sec 1; timeout.tv_usec 0;或用memset(timeout, 0, sizeof(timeout))。4.4 现象客户端发大包64KB时服务器recv()只收到前 65536 字节后续数据丢失原因recv()默认行为是“尽力而为”不保证一次收完。AMF 包体长度字段声明为 100KB但recv()可能只返回 32KB代码未检查n expected就直接解析导致 AMF 解析器崩溃。解决必须用状态机循环recv()直到body_received expected_body_len且每次recv()都检查返回值是否为 0对端关闭或 -1错误。4.5 现象select()返回ret 0但FD_ISSET(fd, read_fds)对所有 fd 都为 false原因fd_set被多个线程共享且未加锁。Flash 服务器虽是单线程但若用了signal()处理SIGCHLD信号处理函数中修改了全局fd_set会导致主循环看到脏数据。解决select()前用sigprocmask()屏蔽信号或确保信号处理函数不操作任何fd_set。5. 从 select 到现代 I/O 模型当 Flash 服务器被迫升级时我们真正放弃的是什么5.1 不是性能而是「状态可见性」这一核心调试优势当某高校实验室将 Flash 服务器迁移到基于epoll的新架构时第一周遇到的最大问题不是吞吐下降而是无法快速定位连接异常。在select模型中gdb附着后执行p/x read_fds.__fds_bits能立刻看到哪些 bit 被置位结合clients[]数组3 秒内可判断“client #237 的 socket 1999 是否在读就绪队列”。而epoll的就绪事件存储在用户提供的epoll_event数组中gdb里只能看到events[0].data.fd 1999但不知道它为何就绪EPOLLINEPOLLOUTEPOLLHUP更无法知道内核红黑树里还有多少未就绪但已注册的 fd。这种「黑匣子感」迫使团队重写日志系统每epoll_wait()返回必须记录events[i].events和events[i].data.fd再关联到clients[]索引。而select时代一行printf(read_fds: %s\n, fdset_to_string(read_fds));就够了。5.2 不是功能而是「超时即心跳」这一简洁设计契约select的timeval参数天然承担了三重角色防止单次select()长期阻塞保障主循环调度驱动心跳检测check_heartbeats_and_timeout()的触发源控制协议解析超时如 AMF 包头 4 字节必须在 5 秒内收齐。迁移到epoll后必须引入timerfd_create()或setitimer()来模拟相同语义代码量增加 3 倍且timerfd的epoll_wait()就绪事件需单独处理破坏了“一个循环处理所有 I/O”的纯粹性。5.3 真正的代价从「确定性」滑向「概率性」的运维心态select模型下服务器行为完全由fd_set状态和timeval决定输入可穷举输出可预测。一个连接断开必然伴随recv()返回 0 或send()返回EPIPEcheck_heartbeats_and_timeout()会在下一个超时周期内发现。这种确定性让运维可以写死监控规则if (active_clients 100) alert(可能有网络分区)。而epoll的边缘触发ET模式下EPOLLIN就绪后若未一次性读完后续不再通知水平触发LT模式下只要缓冲区有数据就持续通知 —— 两种模式都引入了“事件是否被消费完”的隐式状态。当网络抖动导致recv()返回EAGAIN这个EAGAIN是该归因于内核缓冲区空还是客户端发包太慢答案取决于epoll的触发模式、recv()的 flags、以及应用层状态机是否健壮 —— 这不再是确定性问题而是一个概率模型。从那以后我每次重构 I/O 模块都强制走一遍strace -e traceselect,epoll_wait,recv,send对比实验把select版本的read_fds位图和epoll版本的events[]数组逐条对齐确认每一个就绪事件的因果链。不是为了怀旧而是为了守住那条底线当系统开始不可预测工程师的第一反应不该是加日志而是问自己——我们是不是过早放弃了对状态的绝对掌控希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Unity角色跳跃手感优化:输入缓冲、土狼时间与重力曲线实战

Unity角色跳跃手感优化:输入缓冲、土狼时间与重力曲线实战

1. 从一次“手感翻车”说起:为什么你的跳跃总像在月球上做Unity角色控制的人,几乎都经历过同一个尴尬时刻:明明给角色加了跳跃,按下去却像踩在棉花上——要么轻飘飘地飘起来,要么落地时“啪”地一下瞬间贴地&#xff0…

2026/10/18 11:51:17 阅读更多 →
C++网络编程精讲:用长度字段彻底解决TCP粘包与半包问题

C++网络编程精讲:用长度字段彻底解决TCP粘包与半包问题

简介:面向C网络通讯开发者的实战工程,完整演示了从socket初始化、连接建立到消息收发的一整套流程,专门应对TCP协议下粘包与丢包这一棘手问题,尤其适合聊天室、即时通讯或自定义协议系统的开发场景。包体为RAR格式,共3…

2026/10/17 7:01:02 阅读更多 →
扣子技能(Coze Skills)从入门到实操:创建、接入与调试指南

扣子技能(Coze Skills)从入门到实操:创建、接入与调试指南

做扣子Bot有一段时间了,最让我圈粉的功能不是那些花哨的插件,反而是很多人忽略的扣子技能(Coze Skills)。说实话,我刚接触那会儿也懵:技能到底跟插件、工作流有什么区别?为啥有的Bot明明接了技能…

2026/10/17 7:01:02 阅读更多 →

最新新闻

Java麻将胡牌算法:位运算+缓存优化的生产级实现

Java麻将胡牌算法:位运算+缓存优化的生产级实现

简介:本资源是一套面向Java游戏开发与AI算法学习者的麻将核心算法实现合集,聚焦胡牌判定、AI决策、查胡校验、手牌评估及智能出牌五大关键模块,适用于希望深入理解棋牌类游戏逻辑、提升算法设计与工程落地能力的中高级开发者。压缩包共52个文…

2026/10/18 13:06:46 阅读更多 →
VLC 3.0.11 定制版:Win7 下 AVS+ 与 DRA 国标解码实战指南

VLC 3.0.11 定制版:Win7 下 AVS+ 与 DRA 国标解码实战指南

简介:本资源为适配Windows 7及以上系统的VLC媒体播放器增强版(3.0.11),专为需播放国产音视频编码内容的用户设计,尤其适用于广电、IPTV、高校音视频教学及本土化流媒体开发等场景。该版本在开源VLC基础上深度集成AVS视…

2026/10/18 13:06:46 阅读更多 →
HTML5购物网站源码解析:登录、购物车与本地存储实战

HTML5购物网站源码解析:登录、购物车与本地存储实战

简介:这是一套面向前端初学者与进阶练习者的HTML5静态购物网站完整源码,围绕登录注册、商品展示、详情页与购物车等核心模块展开,帮助读者理解从页面搭建到交互逻辑的完整实现路径。压缩包共48个文件,约5.28MB,包含4个…

2026/10/18 13:06:46 阅读更多 →
Flask+WebUploader大文件分片上传实战:断点续传与秒传实现

Flask+WebUploader大文件分片上传实战:断点续传与秒传实现

简介:这是一份面向Python Web开发者的分段上传与流式下载实战示例,基于Flask框架与WebUploader前端组件实现大文件分片上传、服务端合并及低内存流式下载,适合需要处理大文件传输场景的中级开发者参考学习。压缩包共26个文件,约42…

2026/10/18 13:06:46 阅读更多 →
MySQL购物网站数据库设计:事务、锁与防库存超卖完整方案

MySQL购物网站数据库设计:事务、锁与防库存超卖完整方案

简介:MyShop 商城系统数据库设计资源包,面向需完成 MySQL 课程设计、毕业设计或希望掌握电商数据库设计方法的初学者与开发者。资源围绕用户、地址、商品、购物车、订单与订单项六大核心数据模块展开,并从用户管理、商品管理、购物车管理、订…

2026/10/18 13:06:46 阅读更多 →
JMeter并发测试核心参数配置:线程数、Ramp-Up与Duration实战

JMeter并发测试核心参数配置:线程数、Ramp-Up与Duration实战

跑过几次JMeter并发测试之后,你会发现真正决定结果靠不靠谱的,往往不是脚本写得有多花哨,而是线程组里那几个参数怎么搭配。线程数、Ramp-Up、循环次数、Duration,每一项单独看都很好理解,但组合在一起就成了最容易踩坑…

2026/10/18 13:05:46 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →