当前位置: 首页 > news >正文

最小WebSocket服务端骨架

手撸一个能跑的人脸设备 WebSocket 服务端:三阶段状态机实战

讲了一堆协议,不来点能跑的代码总觉得悬。这篇我给一个最小可运行的 Python WebSocket 服务端骨架,把"连接 → 注册 → 登录 → 消息循环"整个状态机跑通。

先说清楚:这是示例实现,生产要补wss/TLS、token 持久化与轮换、并发隔离、限流、消息校验、异常处理。别直接上生产,但拿它理解协议流程够了。

状态机长这样

CloudId 非法

CloudId 合法

token 不符

token 相符

连接建立 CONNECTED

收到 Register?

拒绝并断开

生成 token / 存库 → REGISTERED

收到 Login?

FailUnknownToken 断开

LOGGED_IN 消息循环

TimeLog_v2 → 回 OK + 落库

KeepAlive → 回 OK

其它命令 → 回 OK

代码(Python + websockets)

依赖:pip install websockets

""" 最小 M50 人脸终端 WebSocket 接入服务端(示例实现) 仅用于理解三阶段状态机;生产环境需补充 wss/TLS、token 持久化与轮换、 并发隔离、限流、消息校验、异常处理。 """importasyncioimportbase64importsecretsimportxml.etree.ElementTreeasETimportwebsockets# 模拟数据库VALID_CLOUD_IDS={"cloud-demo-001"}DEVICES={}# serial -> tokendefdecode_name(b64data:str)->str:"""协议里的 Name/部门名是 base64 UTF-16 LE 编码,这里做解码示例"""returnbase64.b64decode(b64data).decode("utf-16-le")defparse(xml_text:str):# 协议样例标签常带不规则空格如 < Subnet >,先规整再解析xml_text=xml_text.replace(" < ","<").replace(" > ",">")returnET.fromstring(xml_text)defbuild(tag,name,trans_id,result,**extra):parts=[f"<{tag}>{name}</{tag}>"]iftrans_id:parts.append(f"<TransID>{trans_id}</TransID>")parts.append(f"<Result>{result}</Result>")fork,vinextra.items():parts.append(f"<{k}>{v}</{k}>")return'<?xml version="1.0"?><Message>'+"".join(parts)+"</Message>"asyncdefhandler(ws):state="CONNECTED"serial=Nonetry:asyncforrawinws:msg=parse(raw)req=(msg.findtext("Request")ormsg.findtext("Event")ormsg.findtext("Response"))trans_id=msg.findtext("TransID")# ---- Register 阶段:校验 CloudId ----ifreq=="Register":ifmsg.findtext("CloudId")notinVALID_CLOUD_IDS:awaitws.send(build("Response","Register",trans_id,"Fail"))returntoken=secrets.token_hex(16)# 服务端生成安全 tokenserial=msg.findtext("DeviceSerialNo")DEVICES[serial]=token state="REGISTERED"awaitws.send(build("Response","Register",trans_id,"OK",Token=token))continue# ---- Login 阶段:校验 token ----ifreq=="Login":ifDEVICES.get(serial)!=msg.findtext("Token"):awaitws.send(build("Response","Login",trans_id,"FailUnknownToken"))returnstate="LOGGED_IN"awaitws.send(build("Response","Login",trans_id,"OK"))continue# ---- 未登录就发业务消息:拒绝 ----ifstate!="LOGGED_IN":awaitws.send(build("Response",reqor"Unknown",trans_id,"Fail"))continue# ---- 已登录:消息循环 ----ifreq=="TimeLog_v2":# 真实项目里这里落库 + 推业务系统(考勤大屏/微信推送)awaitws.send(build("Response","TimeLog_v2",trans_id,"OK"))continueifreq=="KeepAlive":awaitws.send(build("Response","KeepAlive",trans_id,"OK"))continue# 其它命令:示例里原样回 OKawaitws.send(build("Response",reqor"Unknown",trans_id,"OK"))exceptExceptionase:print("conn closed:",e)asyncdefmain():# 注意:示例用 ws:// 方便本地跑,生产必须 wss://asyncwithwebsockets.serve(handler,"0.0.0.0",8765):print("server on :8765 (ws://)")awaitasyncio.Future()if__name__=="__main__":asyncio.run(main())

几个要点(对照前面几篇)

  • TransID必须原样回传——请求和响应靠它关联,也是防重放的基础(安全设计那篇讲过)。
  • CloudId白名单在 Register 阶段就卡掉非法设备,这是租户隔离的第一道闸。
  • tokensecrets.token_hex生成,别硬编码;真实环境存库 + 设过期。
  • TimeLog_v2必须回OK,否则设备可能停止推送(日志接入那篇的坑)。
  • XML 标签不规则空格:协议样例里常写成< Subnet >这种,解析前先.replace(" < ", "<")规整,不然ElementTree解析会出问题。
  • 中文名解码就是base64.b64decode(...).decode("utf-16-le"),一行搞定,但别忘了编码方向。

上生产前你还得补的

  1. 换成wss://(TLS),并开启证书校验(别开AllowNoCertificate)。
  2. token 持久化到数据库,支持轮换和吊销。
  3. 多设备并发:状态要按连接隔离,别用全局变量串台。
  4. 服务器侧限流 + 鉴权,设备会每 10s 重试,别被刷爆。
  5. 业务命令的 handler 一个个补上(人员同步、生物模板、设备控制……),前面每篇的字段细节直接能用。

有了这骨架,把各命令的 handler 填上就是个能用的接入服务。配合前面几篇的字段细节,对接基本没有盲区了。下一篇给一份 46 命令全景速查地图,方便你当字典翻。

http://www.jsqmd.com/news/1306752/

相关文章:

  • 2026年山东及周边不锈钢过滤器选哪家 多场景适配品牌排行 - 甄选测评馆
  • 产后修复哪家好 - 甄选测评馆
  • 2026巴音郭楞全域外墙漏水维修|筑宅安16区上门勘查施工 - 筑宅安
  • 【Linux驱动开发】多节点驱动原理 + file_operations全套接口详解(open/read/write/release)
  • 2026宜宾黄金回收白银回收铂金回收中检持证鉴定师铂金银饰高价回收门店联系方式推荐
  • 证书过期排查:iOS 证书与描述文件检测 API 的工程接入
  • PKHeX-Plugins:从宝可梦数据混乱到专业级管理的完整解决方案
  • 三步搞定Windows 11精简镜像制作:tiny11builder终极实战指南
  • TEMU上架软件:React底层Event注入,表单毫秒级填充
  • 3步解锁B站缓存视频:m4s-converter让你的收藏永不失效
  • 海思、联咏、安霸视觉AI SOC深度对比:选型实战与避坑指南
  • WorkBuddy保姆级教程-从安装到自动化
  • 2026年国内超导电尼龙批发商甄选指南:如何挑选高性价比供应商? - geo交流
  • Honey Select 2终极增强指南:200+插件一键安装,免费解锁完整游戏体验
  • 数据结构中的栈(c)
  • 如何彻底告别Office订阅费用:Ohook终极激活方案完整指南
  • 2026年南京钢管租赁站专业厂家推荐:靠谱供应商怎么选? - 优质品牌商家
  • 英雄联盟多客户端管理终极指南:如何用一个工具同时控制多个游戏账号
  • 银川如何选装修公司?2026最新银川装修品牌三大梯队代表品牌深度测评与盘点 - 甄选测评馆
  • 从“能聊天“到“能干活“:工业智能体和通用智能体到底隔了什么?
  • 2026 年 8 月吴忠市非急救医疗转运行业发展解析及本土合规企业服务实录 - 平台推荐官
  • 深入解析RestTemplate:Java HTTP客户端核心原理、配置优化与实战避坑指南
  • Android开发必备:ADB无线与USB连接抓取Logcat日志全攻略
  • Android Studio Quail3 | 2026.1.3 升级后 Gradle 报错
  • 天赐范式第121天:RBM干预实验怎么干?——从“相关r>0.5“到“因果do算子“的工程推演
  • RAG切块为什么会截断关键证据?用句子边界切分与Anchor回归测试验证知识入库
  • 零配置SQLite JDBC驱动:Java开发者的终极嵌入式数据库解决方案指南 [特殊字符]
  • Python jieba中文分词与词频统计实战:从原理到可视化
  • 影刀RPA新手教程:鼠标点击模式与输入文本指令的选择策略
  • iOS越狱终极指南:解锁iPhone隐藏功能的5个关键步骤