C#多语言房卡棋牌大厅源码架构与断线重连实战
简介这份源码面向C#游戏开发者与棋牌项目学习者提供一套房卡类棋牌游戏大厅的完整实现方案涵盖斗地主、3D麻将红中、血战、广东麻将等及跑得快等玩法并内置茶馆俱乐部社交模块适合用于二次开发、架构参考或课程设计。压缩包共约2000个文件、86.2MB其中214个cs源文件承载核心逻辑834个meta与467个svn-base文件用于资源描述与版本管理另有221个png、65个prefab、51个mat及15个dll等覆盖界面、预制件、材质与依赖库。项目强调多语言适配可按地区切换本地化文案提升国际化体验。目前已有979人学习下载。通过研读目录结构与模块划分读者可掌握大厅框架、游戏接入与社交功能的组织方式理解资源管理与版本协作思路为自研棋牌平台提供可复用的工程参考。1. 房卡棋牌大厅源码到底在解决什么问题做过地方棋牌运营的人都知道真正难的不是写一副麻将的胡牌算法而是把「开房、进房、扣卡、结算、掉线重连」这一整条链路做稳。基于 C# 多语言开发的房卡类棋牌游戏大厅源码本质是一套服务端权威、客户端轻量的房间制游戏框架大厅负责账号、房卡、公告、配置下发游戏服负责具体玩法逻辑客户端只做表现和输入。它解决的是「同一套后端能挂多款玩法、同一份代码能出多语言版本」这两个运营侧最痛的问题。这套东西适合谁一是手里有地方玩法资源、想快速搭一套可运营框架的小团队二是做 C# 上位机、WinForm 工具出身想转游戏服务端但不想从零啃网络库的工程师。它不适合想直接拿成品上线的人——源码是骨架玩法、美术、支付通道都得自己填。下面按「架构怎么搭 → 通信和房间怎么做 → 多语言怎么落地 → 坑在哪 → 怎么验证」的顺序讲透。2. 大厅与游戏服拆分C# 多语言架构的选型理由2.1 为什么大厅和游戏服必须分开进程很多新手第一版会把登录、房间列表、牌局逻辑全塞进一个 exe本地跑没问题一上量就翻车某个玩法死循环把整个大厅拖垮所有玩家连登录都进不去。房卡类棋牌的特点是「玩法多、单局短、房间数波动大」所以常见做法是把系统切成三层。第一层是大厅服Lobby只做无状态或弱状态的事账号注册登录、房卡余额查询、公告、版本更新、房间列表聚合。它可以用 ASP.NET Core 或纯 Socket 都行压力主要来自登录峰值。第二层是游戏服GameServer每个玩法可以独立部署一个或多个实例持有房间内存状态负责发牌、出牌、结算。第三层是数据层账号和房卡走关系库牌局回放和日志走文件或时序库。拆开的核心收益是故障隔离和水平扩展加一个新玩法只要按协议实现一个新的 GameServer大厅几乎不用改。代价是引入了跨进程通信和状态同步的复杂度这也是后面坑最多的地方。2.2 用 C# 泛型与委托搭一套可复用的消息分发C# 做服务端最大的优势是泛型和委托能把「消息号 → 处理函数」这套分发写得非常干净不用满屏 switch。下面是一个最小可用的消息分发器思路是注册时把处理委托按消息号存进字典收到包后反射或直接查表调用。// 消息处理器基类所有玩法协议继承它 public abstract class MessageHandler { public abstract int MsgId { get; } public abstract void Handle(Session session, byte[] body); } // 泛型分发器T 是具体 Handler 类型避免装箱 public class Dispatcher { private readonly Dictionaryint, ActionSession, byte[] _map new Dictionaryint, ActionSession, byte[](); // 注册把 Handler 的 Handle 方法挂到消息号上 public void RegisterT(T handler) where T : MessageHandler { _map[handler.MsgId] handler.Handle; } // 收到网络包后调用msgId 从包头解析 public void Dispatch(Session session, int msgId, byte[] body) { if (_map.TryGetValue(msgId, out var action)) action(session, body); // 命中直接执行 else session.SendError(msgId, unknown msg); // 未注册要回错误别静默丢 } }逻辑说明Register用泛型约束把任意 Handler 塞进字典Dispatch是 O(1) 查表比 switch 更好扩展。参数上MsgId建议用 int 且分段管理比如 1000-1999 给大厅、2000-2999 给麻将、3000-3999 给斗地主避免多玩法消息号撞车。Session封装了 socket 和玩家 uidbody是去掉包头后的负载。提示字典注册要在服务启动时一次性完成运行期不要再增删否则多线程下要加锁得不偿失。2.3 房间对象的生命周期与状态机房间是房卡玩法的核心对象它的状态流转必须显式建模否则「人满了还能进」「结算完没销毁」这类问题会反复出现。常见做法是给房间定义一个枚举状态机等待中、游戏中、结算中、已销毁。只有「等待中」允许加入「结算中」禁止任何出牌请求。public enum RoomState { Waiting, Playing, Settling, Closed } public class Room { public int RoomId; public RoomState State RoomState.Waiting; public ListPlayer Seats new ListPlayer(); public int MaxSeat 4; // 加入房间状态和人数双重校验 public bool TryJoin(Player p) { if (State ! RoomState.Waiting) return false; // 非等待期拒绝 if (Seats.Count MaxSeat) return false; // 满员拒绝 Seats.Add(p); if (Seats.Count MaxSeat) State RoomState.Playing; // 满员自动开局 return true; } }参数说明MaxSeat按玩法配置麻将 4、斗地主 3不要写死。TryJoin返回 bool 而不是抛异常是因为加入失败是正常业务分支异常开销大。状态切换集中在房间内部外部只读State避免多处修改导致状态错乱。2.4 房卡扣减的原子性怎么保证房卡是钱扣减必须原子。新手最容易犯的错是「先查余额 → 再扣 → 再写库」中间任何一步并发都会超扣。正确做法是把扣减下沉到数据库的一条带条件的 UPDATE 语句靠影响行数判断成败。-- 扣房卡余额足够才更新返回受影响行数 UPDATE t_account SET card_balance card_balance - cost WHERE uid uid AND card_balance cost;逻辑说明这条语句在数据库层面是原子的card_balance cost保证不会扣成负数。C# 侧拿到ExecuteNonQuery的返回值等于 1 说明扣成功等于 0 说明余额不足直接给客户端回「房卡不足」。不要用SELECT查余额再判断那是并发超扣的经典翻车点。参数cost按房间类型配置开一局扣几张由运营后台下发别硬编码在代码里。3. 网络通信与断线重连房卡大厅的稳定性命门3.1 选 TCP 还是 WebSocket包头怎么设计棋牌是强顺序、低频率、要求可靠的消息TCP 是默认选择。如果客户端有 H5 版本服务端加一层 WebSocket 网关即可游戏服内部仍走 TCP。包头设计是通信稳定的基础常见做法是「长度 消息号 序列号」三段式。字段长度说明Length4 字节整个包体长度用于粘包拆分MsgId4 字节消息号分段管理Seq4 字节序列号用于请求响应配对和去重Body变长具体协议内容建议 Protobuf粘包处理是 C# 服务端必写的一段收到字节先塞进缓冲区循环判断「缓冲区长度 ≥ 4」就读出 Length再判断「缓冲区长度 ≥ Length」才切出一个完整包否则等下次数据。这段逻辑写错的表现是「偶尔丢包、偶尔解析乱码」属于玄学级 bug一定要写单元测试覆盖半包场景。3.2 断线重连状态快照比补发消息更靠谱玩家手机切后台、地铁进隧道断线是常态。房卡玩法里断线重连做不好玩家回来发现牌不对直接投诉。两种方案一是补发断线期间的所有消息二是重连时直接下发一份房间状态快照。我一般选快照因为补发要维护消息队列内存和逻辑都重快照只要序列化当前房间对象。// 重连时构造快照下发客户端整体覆盖本地状态 public object BuildSnapshot(Room room, int uid) { return new { roomId room.RoomId, state room.State.ToString(), // 只下发自己的手牌别人的牌不能给 myCards room.Seats.First(s s.Uid uid).HandCards, // 其他玩家只给数量和出牌记录 others room.Seats.Where(s s.Uid ! uid) .Select(s new { s.Uid, count s.HandCards.Count }), lastPlay room.LastPlayRecord }; }逻辑说明快照的关键是「只给自己看自己的牌」myCards单独取others只暴露数量。参数lastPlay是最近一次出牌记录客户端用它恢复桌面。重连流程是客户端带 uid 和 roomId 重连 → 服务端校验该 uid 是否还在房间 → 在则下发快照不在则回「房间已结束」。注意快照下发后要重置该玩家的心跳计时否则会被误判离线踢掉。3.3 心跳与超时踢人的参数怎么设心跳间隔设太短浪费流量设太长掉线发现慢。移动端常见做法是客户端每 5 秒发一次心跳服务端超过 15 秒没收到就标记离线超过 60 秒还没重连就移出房间。这三个参数要能配置不同网络环境调优。// 心跳检测定时器每 5 秒扫一遍所有 session private void CheckHeartbeat() { var now DateTime.UtcNow; foreach (var s in _sessions.Values) { var idle (now - s.LastActive).TotalSeconds; if (idle 60) s.Close(timeout); // 超 60 秒踢出 else if (idle 15) s.MarkOffline(); // 超 15 秒标离线 } }参数说明LastActive在每次收到任何包时更新不只是心跳包。MarkOffline只改状态不移除给重连留窗口。定时器用单个后台线程扫别每个 session 起一个 Timer那是 WinForm 控件多导致卡顿的同款翻车——线程和定时器数量要可控。注意踢人前要先把该玩家在房间里的状态置为「离线托管」直接移除会导致其他玩家看到的座位数对不上。4. 多语言落地不是翻译文案那么简单4.1 多语言的三层文案、协议、玩法配置很多人以为多语言就是把界面文字换成英文实际上一套棋牌源码要做多语言至少三层都要处理。第一层是 UI 文案用资源文件按语言 key 索引。第二层是协议字段比如错误码要能映射到不同语言的提示。第三层最容易被忽略——玩法配置比如某些地区玩法规则不同配置表要按语言或地区分目录。C# 里做文案多语言标准做法是.resx资源文件按 culture 命名运行时用ResourceManager按当前 culture 取。但棋牌大厅的文案量大且要热更我一般不用 resx而是用 JSON 配置表服务端和客户端共用一份改文案不用重新编译。// 多语言文案加载按语言加载 JSON 字典 public class LangService { private Dictionarystring, string _dict new(); public void Load(string lang) // lang 如 zh-CN en-US { var path $lang/{lang}.json; var json File.ReadAllText(path); _dict JsonSerializer.DeserializeDictionarystring, string(json); } // 取文案缺失时回退到 key 本身方便发现漏翻 public string T(string key) _dict.TryGetValue(key, out var v) ? v : key; }逻辑说明Load按语言加载对应 JSONT是取文案的统一入口。参数lang由客户端登录时上报服务端存到 session 里后续下发公告、错误提示都按这个语言走。缺失回退到 key 本身是为了测试期一眼看出哪条没翻译别回退成空字符串。4.2 协议错误码的多语言映射服务端返回错误时只回错误码不回文案文案由客户端按当前语言渲染。这样服务端不用关心语言客户端切换语言也不用重连。错误码表建议单独维护一份中英各一列。错误码zh-CNen-US1001房卡不足Not enough cards1002房间已满Room is full1003不在该房间Not in this room1004操作过于频繁Too frequent这张表放在客户端资源里服务端只发 1001 这样的数字。好处是加语言只改客户端资源服务端零改动。注意错误码要全局唯一别大厅和游戏服各用一套否则客户端映射会撞。4.3 玩法配置按地区分目录的实践地方棋牌的特点是「同一个名字规则不同」。比如「跑得快」在不同地区张数和炸弹规则都不一样。做法是把玩法配置按game/{gameType}/{region}.json组织房间创建时带上 region 参数服务端加载对应配置。// 按玩法和地区加载规则配置 public GameRule LoadRule(string gameType, string region) { var path $config/game/{gameType}/{region}.json; if (!File.Exists(path)) path $config/game/{gameType}/default.json; // 回退默认 var json File.ReadAllText(path); return JsonSerializer.DeserializeGameRule(json); }参数说明gameType是玩法标识如paodekuairegion是地区标识。回退到 default 保证新地区没配也能跑。GameRule里放张数、炸弹规则、结算倍数等。这套结构让运营加一个地区玩法只加一个 JSON不用改代码这是多语言多地区棋牌能规模化的关键。5. 避坑与排查房卡大厅源码最容易翻车的五处5.1 现象玩家反馈「牌局结算后房卡没扣」原因扣卡逻辑写在了结算之后且没有事务包裹结算成功但扣卡那步抛异常被吞掉。解决把扣卡放在开局时扣或者用数据库事务把结算和扣卡绑在一起任何一步失败整体回滚。我一般选开局扣逻辑简单退款场景单独处理。5.2 现象多玩法上线后消息号冲突A 玩法的包被 B 玩法处理原因各玩法独立开发消息号都从 1000 开始编。解决消息号分段管理写进团队规范大厅 1000 段、每个玩法分配独立千位段注册时如果发现消息号已存在直接启动报错别让它静默覆盖。5.3 现象断线重连后玩家手牌显示成别人的原因快照构造时用了room.Seats[0]这种按座位取没按 uid 匹配重连玩家座位变了就取错。解决所有取自己数据的逻辑一律用 uid 匹配禁止用座位下标。座位下标只用于展示顺序不用于身份识别。5.4 现象服务端跑几天内存持续上涨原因房间结算后没从房间字典移除或者移除后事件委托没解绑房间对象被委托引用着无法回收。解决房间销毁时显式从字典Remove并把房间内所有事件订阅解绑。用WeakReference或定期 dump 堆排查别靠猜。5.5 现象客户端切语言后部分文案还是旧语言原因文案在登录时加载一次后缓存切语言没重新加载或者部分文案硬编码在代码里没走T()。解决切语言时清缓存重新Load并全局搜索硬编码字符串所有面向玩家的文字必须走统一入口。硬编码是多语言项目最大的技术债。6. 上线前怎么验证这套源码值不值得投入验证一套房卡棋牌大厅源码别只看能不能跑起来要看它在压力和多语言切换下的表现。我一般做三件事。第一件是并发开房压测用脚本模拟 200 个玩家同时开 50 个房间观察房卡扣减是否精确、有没有超扣或漏扣。第二件是断线重连遍历随机在牌局各阶段断线重连检查快照是否一致这一步能揪出大部分状态同步 bug。第三件是多语言切换回归中英来回切逐屏检查文案和错误提示。下面这段是并发扣卡的验证脚本思路用 C# 起多线程打同一个账号看最终余额是否等于初始减总消耗。// 并发扣卡验证100 个线程各扣 1 张初始 50 张 int success 0; Parallel.For(0, 100, _ { // DeductCard 内部走带条件的 UPDATE返回是否成功 if (AccountService.DeductCard(uid, 1)) Interlocked.Increment(ref success); }); // 正确结果success 50余额 0绝不能为负 Console.WriteLine($成功扣减 {success} 次);逻辑说明Parallel.For起 100 个并发DeductCard走前面那条带card_balance cost的 SQL。正确结果是成功次数等于初始余额 50余额归零且不为负。如果成功次数大于 50说明扣卡逻辑有并发漏洞必须回去查 SQL 条件。这个测试跑通房卡这条最要命的链路才算稳。一个具体技巧把房间快照和扣卡日志都落一份到本地文件出问题时能对着时间线复盘比翻数据库日志快得多。我吃过没日志的亏线上一个「牌不对」的投诉查了三天最后发现是重连时快照少发了一个字段。从那以后凡是涉及状态同步的地方我都强制打点宁可多写几行日志也不给自己留后悔药没得吃的情况。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

反转字符串中的单词:双指针原地算法与边界条件全解析

反转字符串中的单词:双指针原地算法与边界条件全解析

反转字符串中的单词这道题,几乎是所有刷力扣的人都会遇到的一道“入门级中等题”。说是中等,其实难点不在算法本身,而在你对字符串操作的熟练度、对边界条件的敏感度,以及能否在设计解法时跳出“从头到尾处理”的惯性思维。我刷这…

2026/10/4 4:04:04 阅读更多 →
AI-For-Beginners 课程实战:预训练网络与迁移学习,让 ImageNet 知识为你所用

AI-For-Beginners 课程实战:预训练网络与迁移学习,让 ImageNet 知识为你所用

教程人工智能机器学习深度学习 【免费下载链接】AI-For-Beginners 12 Weeks, 24 Lessons, AI for All! 项目地址: https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners 点击查看 免费下载 在计算机视觉领域,从零训练一个卷积神经网络(…

2026/10/4 4:04:04 阅读更多 →
Linux信号机制详解:从内核流程到sigaction与EINTR实战

Linux信号机制详解:从内核流程到sigaction与EINTR实战

接触Linux系统编程的人,大概率都有过被信号支配的经历:终端里按一下CtrlC程序没了,write管道时程序莫名其妙退出,后台守护进程被killall之后变得半死不活。信号这东西在系统编程里绕不开,它说简单也简单,无…

2026/10/4 4:04:04 阅读更多 →

最新新闻

单片机AT指令非阻塞配置模块模板:状态机与超时重试机制

单片机AT指令非阻塞配置模块模板:状态机与超时重试机制

搞单片机开发的朋友,十有八九都跟AT指令打过交道。WiFi模块要配ESP8266,蓝牙模块要配HC-05,4G模块要配EC200,GPS模块要配ATGM336H,甚至不少传感器模块都爱用AT指令来设置参数。AT指令本身逻辑很简单,就是“…

2026/10/4 4:41:25 阅读更多 →
Xilinx FPGA上MIPI DPHY接口实战:从CSI-2采集到DSI显示的全流程解析

Xilinx FPGA上MIPI DPHY接口实战:从CSI-2采集到DSI显示的全流程解析

/* 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 4:41:25 阅读更多 →
复合光源仿真实用指南:VirtualLab Fusion建模全流程解析

复合光源仿真实用指南:VirtualLab Fusion建模全流程解析

做光学系统仿真的人,早晚都会卡在光源这一步。单色平面波确实能解决很多衍射、干涉问题,可一旦你开始处理真实光源——白光LED、多模激光二极管、宽谱超连续谱——就会发现结果怎么都对不上实验,干涉条纹宽度不对、对比度偏大、色散效应完全看…

2026/10/4 4:41:25 阅读更多 →
STM32电梯面板开发实战:从硬件选型到RS485通讯与状态机设计

STM32电梯面板开发实战:从硬件选型到RS485通讯与状态机设计

前阵子帮朋友处理一栋老写字楼的电梯召唤盒问题时,我蹲在门口拆开那台用了十几年的设备,里面是一排继电器和一堆已经发黑的触点。电梯每停一层,盒子里的继电器就噼里啪啦响一阵,楼层指示灯用的小灯泡也黑了两只。我当时就跟朋友说…

2026/10/4 4:41:25 阅读更多 →
分支功能:实现脚本多场景覆盖

分支功能:实现脚本多场景覆盖

分支功能:实现多场景覆盖主线描述脚本要做的功能,分支描述该功能在各条路径上的执行情况。 一份代码,配上 N 个分支场景,得到 N 份测试结论。 项目地址:https://qingxun.online一、问题:脚本在正常情况下通…

2026/10/4 4:41:25 阅读更多 →
Oil Motion三大交付路线全解析:烘焙视频、绿幕视频与透明雪碧图如何自动选型

Oil Motion三大交付路线全解析:烘焙视频、绿幕视频与透明雪碧图如何自动选型

Oil Motion三大交付路线全解析:烘焙视频、绿幕视频与透明雪碧图如何自动选型 【免费下载链接】oil-motion 设计并实现随滚动、拖动、指针或状态变化响应的网页动画,覆盖素材、时间轴和运行时。 项目地址: https://gitcode.com/gh_mirrors/oi/oil-motio…

2026/10/4 4:40:24 阅读更多 →

日新闻

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/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →