车间里的计算终端不是手机:是挂着扫码枪、刷卡器、标签打印机的工控机,对面还连着注塑机的 PLC。给这种环境做终端,问题清单和互联网 App 完全不同——怎么让 Web 页面摸到串口和 PLC?软件凭什么能”卡住”一台几百吨的机器?断网之后终端还剩什么?
本篇是端侧线的开篇,拆这套系统的工控终端:一个 C# WPF 壳应用,内嵌浏览器加载云端 MES 页面,自己只做三件事——硬件桥接、防呆联锁、离线兜底。它的规模很小(几十个手写类),但每一类都是后端工程师平时碰不到的问题域;上一篇交付篇把它列为第三种交付形态,本篇把它拆开。
一、壳的哲学:Web 复用加本机硬件桥接
先立架构观。壳里是内嵌 Chromium(CefSharp),加载的 MES 页面和 PC 浏览器里的是同一套——业务 UI 零开发,云端页面升级即终端升级。壳的价值全部在 Web 够不到的地方:串口、PLC、打印机、本地文件。它向网页暴露一个注册对象,方法清单按职能分四类:状态属性(设备编号、工位、菜单权限、面板通断锁状态)、打印(PDF 静默直出、打印机枚举)、外设(串口消息、读卡)、运维(缓存清理、检查更新、重启进程)。
网页和壳的通信模型值得停下来看,因为它和 Web 开发的直觉不同:没有 Promise,没有回调注册——用的是”属性共享 + 反向钩子”模型。壳把注册对象的属性直接暴露给 JS 同步读(卡号、菜单清单、打印机名),操作结果不通过返回值回传,而是壳反向调用网页上的约定钩子函数(刷卡完成调 setCardNo、PLC 连接状态变化调 setVuePanelState)。这个”土模型”的成因是 CefSharp 的版本演进:老的注册 API 和新的对象仓库 API 绑定行为不同,升级到 96 版后必须打开旧式绑定兼容开关,否则线上所有 JS 绑定静默失效——一个兼容开关决定整套桥的生死,这是壳应用升级最真实的坑。
二、锁机防呆:软件凭什么卡住一台注塑机
壳里最”硬”的能力是锁机:MES 判定不该生产时(未过首检、停机超时、转产未确认),工控机直接向注塑机 PLC 发指令禁止锁模——软件卡生产,卡的其实是”人绕过系统”的可能。
实现上没有引协议栈,而是预置十六进制命令帧的裸 Socket:配置文件里存着两条完整的 Modbus 写单线圈帧(从站地址、线圈地址、通断值、CRC 校验),一条锁、一条解,发送即生效。这个”土办法”的合理性值得体会:命令帧固定不变、写死进配置反而可审计——现场能核对每一字节的含义。
防呆联锁的架构原则在交付篇立过,这里给它的完整表述:执行与决策分离。壳只做执行器(收命令、写线圈),解锁的决策权在 MES 状态机——首检合格、扫码确认后由平台放行,PAD 无权自行解锁。这条边界如果破了(壳里藏解锁逻辑),整个防呆体系就退化为装饰。配套的还有通断状态监控:定时 Ping PLC,连接状态实时推给 MES 页面显示——执行器自身的健康度也要上报,否则”锁机失败”会和”没有锁机指令”混在一起。
这块代码也留着工控软件的典型病:发送后睡五百毫秒再同步收响应(UI 线程阻塞风险)、失败在 catch 里递归重发自己(断线时无限递归的隐患)。工控代码的”能跑”和”健壮”之间隔着工位断电、网线松动、PLC 重启的一百种组合——这些坑我在面试里讲过,比任何设计模式都让面试官相信你碰过真设备。
三、PLC 调试台:第二条通道与离线闭环
壳里藏着一个独立的小世界:悬浮”换模调试”窗。它是双通道设计的第二条通道——锁机走 Modbus 固定帧,工艺参数调试走另一条 JSON-over-TCP 通道(直连 PLC 网关,消息带类型标记双向回推)。
调试窗本身就是一次架构自洽的示范:它内部又开了一个浏览器,加载的是本地打包的 Vue 页面(不依赖服务器),按钮清单从本地配置文件读——配置协议是五组按钮描述(参数输入框、按住型操作钮、双态开关、单选组……每组带指令码和参数值),页面按描述动态渲染。链路完整走一遍:调试页点”吹气时间”按钮 → JS 调壳的桥 → 壳打包 JSON 发 TCP → PLC 网关回推实际值 → 壳回显到页面并写入本地 SQLite。
SQLite 那一笔是点睛之笔:工艺参数的每次读写都留了本地副本,调试窗初始化时从本地库还原上次的全部参数——于是整个 PLC 调试闭环(看参数、改参数、回显)在 MES 完全断网时照常工作。车间网络是最不可靠的网络,”断网还能干什么”是工控终端的设计底线:主业务可以死,调试和防呆必须活着。
四、刷卡登录:硬件到卡号,会话归浏览器
登录流程的分工同样干净。壳并行初始化三套读卡硬件(IC 卡轮询线程、身份证读卡定时器、高频 RFID 串口),任何一个读到卡号,统一落进桥对象的卡号属性、调网页钩子通知——然后壳就退场了:登录接口的调用、会话的建立全由 MES 前端自己完成。壳对会话的唯一参与是零代码的:内嵌浏览器的磁盘缓存天然持久化登录 Cookie,工控机重启后登录态还在。
“硬件到卡号为止”的分工有个容易忽视的好处:换一种登录方式(改扫码、加人脸),壳一行不改。硬件桥接层和业务层的边界划在”卡号”这个最小公约数上——和后端集成里”传键不传宽结果”(边界篇)是同一条原则在端侧的投影。
这一层也有工控环境的经典坑:三套读卡器加通用串口各自打开配置里的串口,串口独占冲突靠人工把设备错开不同口、加开关逐个启停;关机时要按顺序停四个硬件线程,漏一个下次启动就抢不到口。现场表现是玄学的”扫码枪没反应但程序一切正常”——工控调试的一半时间在跟这类资源独占搏斗。
五、升级与多环境:把运维做给现场
工控机的运维对象是”没有任何技术背景的产线文员”,所以升级和环境切换被设计成了傻瓜流程:
多环境切换:壳启动时从云端拉服务器列表(多套环境条目:名称、地址、升级源),首次开机渲染成选择列表,选中后写回本地配置并重启进程——换环境不需要改任何配置文件。版本升级:启动时向云端校验版本号,比出新版弹窗、流式下载安装包、启动安装并自杀进程——即装即更新的安装包形态,而不是开发同学熟悉的增量热更。配置下发:菜单和按钮的可见性由云端配置驱动,产线工位的终端只见报工和提报按钮——按钮清单按工位下发,这是”端上能力云端定义”(交付篇)在终端层的完成态。
代码里还留着一次方案演化的化石:悬浮调试窗最早是原生 WPF 按钮实现,后来整个换成本地 H5 页面(原生版代码保留未删)——连工控终端的 UI 也在从原生走向 Web,理由和主壳一样:改页面不用发版。
六、面试视角:六个问题拆到底
Q1:车间终端为什么用壳加载 Web,而不是原生开发?
答:演化速度和硬件桥接的平衡。业务页面在云端以周为单位变,壳的能力(串口、PLC、打印)以年为单位稳定——壳只做 Web 够不到的事,两边发布节奏互不拖累。证据是终端 UI 自己也在原生改本地 H5:Web 化的压强最终会传到终端,壳架构让这层压强只作用于”本地页面”而不是整个应用。
Q2:网页和壳怎么通信?为什么不用 Promise?
答:属性共享加反向钩子:壳把状态对象注册给 JS 同步读,操作结果通过壳反向调用网页上的约定钩子函数回传。不用 Promise 的原因是 CefSharp 绑定 API 的版本演进——新老 API 的绑定行为不同,升级时必须打开旧式绑定兼容开关,桥模型跟着 API 世代走。教训是桥协议一旦被网页大范围消费,演进就只能靠兼容开关,所以桥方法要设计得尽量”哑”。
Q3:软件怎么”卡住”一台注塑机?防呆的边界在哪?
答:预置十六进制命令帧的裸 Socket 直写 PLC 线圈(锁与解各一条固定帧,可审计),断线用定时 Ping 监控并上报页面。防呆的边界是执行与决策分离:PAD 只做执行器,解锁决策在 MES 状态机(首检合格、扫码确认才放行),壳里不藏任何解锁逻辑——这条边界破了,防呆就退化为装饰。
Q4:断网之后终端还能干什么?
答:设计底线是”主业务可以死、调试和防呆必须活着”。PLC 调试窗加载本地页面、按钮清单读本地配置、参数读写本地 SQLite(每次 PLC 回推都留副本)、指令直发 PLC——整个调试闭环离线可用;锁机是壳与 PLC 的直连,也不依赖服务器。依赖云端的部分(报工、报表)断网即不可用,这是有意的:防止离线数据与账本漂移。
Q5:刷卡登录的会话怎么管理?
答:壳只负责”硬件到卡号”:三套读卡硬件统一把卡号写进桥属性、调钩子通知网页,登录接口与会话由前端自己完成;Cookie 靠内嵌浏览器的磁盘缓存天然持久化,壳零会话代码。这个最小公约数分工的好处是换登录方式壳不改——硬件桥接层和业务层在”卡号”处解耦。
Q6:工控软件有哪些互联网开发碰不到的坑?
答:串口独占(多套外设抢口,靠错口加开关人工管理,关机要按序停线程);UI 线程阻塞(Modbus 同步收发加睡眠,正确做法是异步化);失败重试写成了 catch 里递归调自己(断线时无限递归);还有兼容开关类故障(浏览器内核升级让全部 JS 绑定静默失效)。共同点是这些故障的现场都在物理世界里,复现要靠设备组合,所以工控代码的防御性设计要按”设备一定会以你没想到的方式失效”来做。
小结
- 壳的三件事:硬件桥接、防呆联锁、离线兜底——业务 UI 一行不写,云端页面升级即终端升级;
- 桥模型是属性共享加反向钩子:没有 Promise 的土模型,是被浏览器内核 API 世代绑架后的务实选择,桥方法要设计得”哑”;
- 执行与决策分离是防呆的第一原则:软件卡生产卡的是绕过系统的可能,PAD 无权解锁;
- 锁机走固定帧、调试走 JSON 通道:双通道按变更频率分流,固定帧可审计、JSON 可扩展;
- 断网底线:PLC 调试闭环靠本地页面加本地 SQLite 完全离线可用,主业务有意不提供离线——防离线数据与账本漂移;
- 硬件桥接止于最小公约数(卡号、参数值):登录方式、业务语义的变更永远烧不到壳;
- 工控代码的健壮性按”设备一定以没想到的方式失效”设计:串口独占、UI 阻塞、递归重试,每个坑的现场都在物理世界。
下一篇预告:电子看板形态史——十七个 Controller 的可配置看板体系、日预聚合表扛数据量、MAC 白名单代替登录态的”无人大屏”鉴权、three.js 的 3D 车间监控,与横河 Android APK 的多端形态。