ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OctoPrint JS 客户端库 Socket 模块完全指南:SockJS 实时通信、消息订阅与通信节流机制

OctoPrint JS 客户端库 Socket 模块完全指南:SockJS 实时通信、消息订阅与通信节流机制 物联网后端【免费下载链接】OctoPrintOctoPrint is the snappy web interface for your 3D printer!项目地址https://gitcode.com/gh_mirrors/oc/OctoPrint点击查看免费下载本文围绕 OctoPrint JavaScript Client Library 中的OctoPrintClient.socket组件展开系统讲解如何通过 SockJS 建立与 OctoPrint 服务器的实时双向通信通道涵盖连接选项、消息收发与订阅、带身份认证的 Socket 连接示例以及客户端自适应的通信节流Communication Throttling原理。读完本文你将能够在自己开发的 Web 前端或第三方客户端中正确接入 OctoPrint 的推送通道并理解其背后的源码实现细节。一、Socket 组件在 JS 客户端库中的定位OctoPrint 通过 SockJS 实现服务器向客户端推送状态更新、温度变化、事件通知等实时数据。JS Client Library 将这一能力封装为OctoPrintClient.socket组件源码位于 src/octoprint/static/js/app/client/socket.js注册方式为OctoPrintClient.registerComponent(socket, OctoPrintSocketClient)。使用 Socket 组件之前需要先引入 JS 客户端库及其依赖。根据 docs/jsclientlib/index.rst 的说明在 OctoPrint 的 Jinja2 模板中最稳妥的引入方式是使用 assets 标签让 OctoPrint 自动处理 URL 前缀{% assets js_client %}script typetext/javascript src{{ ASSET_URL }}/script{% endassets %}由于 Socket 组件依赖 SockJS还需要额外引入script src{{ url_for(static, filenamejs/lib/sockjs.min.js) }}/script引入后全局变量OctoPrint即为预置的客户端实例可直接通过OctoPrint.socket访问 Socket 组件若需要连接多个服务器则可自行new OctoPrintClient({baseurl: ..., apikey: ...})创建实例。二、Socket 客户端选项optionsOctoPrintClient.socket.options是 Socket 组件的核心配置对象各选项及其默认值如下表所示选项默认值含义timeouts[1, 1, 2, 3, 5, 8, 13, 20, 40, 100]断线后依次尝试重连的等待时间序列单位秒共 10 次尝试失败后放弃connectTimeout5000初始连接超时毫秒即等待 SockJS 进入 connected 状态的最长时间与具体传输方式无关transportTimeout4000传输层超时毫秒即 SockJS 等待初始 WebSocket 连接成功后才降级到较慢但可能可用的其他传输方式rateSlidingWindowSize20参与时序分析与通信节流的最近速率测量样本数量在 socket.js 中可以看到这些默认值的实际定义。注意源码中timeouts数组首项实际为0立即尝试首次重连即完整序列为[0, 1, 1, 2, 3, 5, 8, 13, 20, 40, 100]这与文档记载的前几次快速连接失败后逐渐退避、10 次尝试后放弃的行为一致。关于transportTimeout源码注释给出了明确的设置动机socket.jsSockJS 默认的传输超时仅约 200ms这个值过低会导致远程部署的 OctoPrint 插件或远程连接被迫过早降级到基于 HTTP 轮询的劣质传输方式也会让低性能设备在 OctoPrint 初始加载时因请求涌入处理不及而受影响。因此 OctoPrint 将默认值提高到 4000ms。三、连接生命周期connect / reconnect / disconnect3.1 connect(opts)OctoPrint.socket.connect(opts);connect()将 Socket 客户端连接到 OctoPrint 的 SockJS 端点实际 URL 为baseurl sockjs。可选参数opts会透传给 SockJS 构造函数用于提供额外配置其中connectTimeout与transportTimeout两个键会被客户端提取出来覆盖自身对应选项其余键则作为 SockJS 选项如timeout传递。调用connect()时客户端会先执行一次disconnect()以确保不会重复建立连接。连接建立后onOpen回调会将reconnecting标志复位、reconnectTrial归零并触发onConnected()。3.2 断线重连机制Socket 客户端内置了自动重连逻辑。当连接关闭且关闭码不是正常的 1000normalClose时onClose回调会依次执行触发onReconnectAttempt(trial)钩子——若返回true则放弃本次自动重连例如 UI 已主动断开触发onDisconnected(code)通知连接已断开若reconnectTrial timeouts.length按timeouts[reconnectTrial]秒延时后调用reconnect()并递增尝试计数尝试次数用尽后触发onReconnectFailed()。OctoPrint.socket.reconnect(); // 立即重连若当前已连接则先断开 OctoPrint.socket.disconnect(); // 主动断开连接reconnect()的实现是先disconnect()再重新connect()即断开现有连接后重建。上述钩子onReconnectAttempt、onReconnectFailed、onConnected、onDisconnected、onConnectTimeout在源码中均有对应的空实现可被继承覆写。3.3 连接超时connectTimeout到期后触发onConnectTimeout()。客户端内部在收到connected消息时会清除该超时定时器确保连接成功后不会误报超时。四、消息收发onMessage / removeMessage / sendMessage / sendAuth4.1 注册与移除消息处理器OctoPrint.socket.onMessage(message, handler); OctoPrint.socket.removeMessage(message, handler);onMessage(message, handler)为指定类型的消息注册处理器。handler接收一个对象参数eventObj其中event属性为接收到的消息类型data属性为接收到的载荷如有。注册类型为*时可捕获所有消息OctoPrint.socket.onMessage(*, function(message) { // do something with the message object });removeMessage(message, handler)用于注销处理器必须传入与注册时相同的函数引用才能正确移除const handler (message) { // do something with the message object }; OctoPrint.socket.onMessage(*, handler); // 使用同一个函数引用进行移除 OctoPrint.socket.removeMessage(*, handler);从源码实现看onMessage将处理器按消息类型分组存放于registeredHandlers中并返回this支持链式调用propagateMessage在派发消息时会先调用所有*通配处理器再调用该类型专属的处理器。同时它会记录从开始派发到全部处理器执行完毕所耗的时间并交给analyzeTiming做速率分析——这正是通信节流见第六节的测量基础。OctoPrint 服务器推送的消息类型定义在 docs/api/push.rst主要包括connected建立连接后立即发送的初始连接信息版本、分支、插件哈希、配置哈希等reauthRequired当前会话需要重新认证reason取值logout、stale、removed表示需要完整主动登录其他值则被动登录即可current限流后的通用状态更新打印机状态、任务进度、累积的温度点与日志行服务器最多每秒推送两次history建立连接初期发送的状态、温度与日志历史使客户端快速同步到最新状态eventOctoPrint 内部触发的事件如PrintFailed、MovieRenderDoneslicingProgress后台切片任务的进度更新plugin由插件生成的消息载荷结构由插件自行定义。客户端必须忽略任何未知类型的消息。4.2 向服务器发送消息OctoPrint.socket.sendMessage(type, payload);sendMessage将{type: payload}序列化为 JSON 后通过 Socket 发送。目前 OctoPrint 服务器仅支持throttle和auth两种客户端到服务器的消息此外 1.8.0 起还支持subscribe但 JS 客户端库本身未封装该方法需直接通过 Socket 原始发送OctoPrint.socket.sendAuth(userId, session);sendAuth(userId, session)是sendMessage(auth, userId : session)的便捷封装见 socket.js。其中session必须是从OctoPrint.browser.login(...)或被动登录响应中取得的session字段值。服务器端对auth消息的解析位于 src/octoprint/server/util/sockjs.py消息格式为userId:session服务器用validate_user_session校验用户与会话校验失败会触发_on_logout并下发reauthRequiredreason 为stale。校验成功后该连接便与用户会话绑定从而具备推送消息所需的权限。4.3 与 Push API 的对接auth、throttle、subscribe三种客户端消息在 docs/api/push.rst 中有完整规范auth格式为someuser:LGZ0trf8By用于把已有用户会话关联到 Socket。由于权限系统会阻止缺少STATUS权限的客户端接收任何状态消息auth对接收消息至关重要throttle一个整数乘数作用于 500ms 的基础限流间隔。值为2表示最多每 1s 一条消息值为3表示最多每 1.5s 一条以此类推{throttle: 2}subscribe1.8.0选择性订阅某些消息类型支持state含logs/messages的布尔或正则过滤、plugins、events。发送subscribe后连接将不再默认接收所有消息且后发的subscribe会整体替换之前的订阅。五、建立带认证的 Socket 连接完整示例5.1 使用用户名与密码OctoPrint.socket.connect(); OctoPrint.browser.login(myusername, mypassword, true) .done(function(response) { OctoPrint.socket.sendAuth(myusername, response.session); });先建立 Socket 连接再通过 OctoPrintClient.browser 的login方法完成主动登录并取得会话随后将用户名与会话发送给服务器完成 Socket 认证。login的第三个参数remember为true时会话可跨浏览器重启持久化。5.2 仅使用 API Keyvar client new OctoPrintClient({ baseurl: http://example.com/, apikey: abcdef }); client.socket.connect(); client.browser.passiveLogin() .done(function(response) { client.socket.sendAuth(response.name, response.session); });当只有 API Key 而没有用户名密码时通过passiveLogin()实现见 src/octoprint/static/js/app/client/browser.js利用现有 Cookie 会话完成被动登录再从响应中取name与session进行 Socket 认证。注意client为独立实例其baseurl需指向目标 OctoPrint 服务器。六、通信节流Communication Throttling机制6.1 设计目标与测量原理Socket 客户端内置了通信节流能力。OctoPrint 默认以每 500ms 一条消息的速率推送current状态更新服务端_base_rate_limit 0.5秒见 sockjs.py但对于处理能力不足的客户端仍然可能过快。节流的测量方式客户端记录每个传入消息被所有已注册处理器处理完毕所花费的时间并放入一个长度为rateSlidingWindowSize默认 20的滑动窗口rateLastMeasurements。之后基于以下两条规则决策见 socket.js处理太慢降速某次测量值大于当前处理上限rateThrottleFactor * rateBase即当前节流因子 × 500ms说明消息处理跟不上当前速率触发onRateTooHigh(measured, maximum)默认实现调用decreaseRate()处理太快提速仅当节流因子rateThrottleFactor 1时评估若滑动窗口内最大处理时间仍小于下限(rateThrottleFactor - 1) * rateBase说明当前速率已远低于客户端处理能力触发onRateTooLow(measured, minimum)默认实现调用increaseRate()。6.2 速率调整指令OctoPrint.socket.increaseRate(); // 通知服务器将消息速率提高 500ms OctoPrint.socket.decreaseRate(); // 通知服务器将消息速率降低 500ms两个方法通过sendThrottleFactor()向服务器发送throttle消息increaseRate()将rateThrottleFactor减 1下限为 1此时不再发送decreaseRate()将其加 1。服务端在 sockjs.py 中校验该整数必须 1否则忽略并记录告警随后将_throttle_factor用于current消息的发送节奏控制结合_held_back_current定时器实现限流。6.3 自定义节流策略onRateTooLow(measured, minimum)与onRateTooHigh(measured, maximum)均可被覆写以便实现自定义的速率调整策略例如接入自己的节流算法而非使用默认的增减 500ms 逻辑回调触发条件参数onRateTooLow整个滑动窗口内消息往返处理时间均低于当前速率所需的下限measured窗口内最大消息处理时间minimum维持当前速率的下限onRateTooHigh最近一次消息处理时间高于当前速率上限measured本次消息处理时间maximum维持当前速率的上限6.4 服务端视角的节流协作节流并非单方面行为。服务端PrinterStateConnection见 sockjs.py在推送current时校验连接用户是否具备STATUS权限无权限则直接跳过校验订阅状态——若客户端启用了订阅但不含state则不推送状态更新按_base_rate_limit * _throttle_factor计算发送间隔若距离上次发送不足间隔则用threading.Timer将本次更新推迟到间隔满后再发从而保证推送频率不超出客户端协商的速率。此外未认证连接的消息会被放入最多 100 条的_unauthed_backlog队列暂存待auth成功后再补发见 sockjs.py这也是先connect()再sendAuth()这一标准流程能够可靠工作的原因之一。七、常见实践要点与注意事项权限前置auth消息应在subscribe之前发送如需选择性订阅则先subscribe后auth且必须持有STATUS权限才能收到状态类推送重连处理正常关闭code 1000不会触发自动重连非正常断开后客户端会按timeouts序列自动退避重试可通过覆写onReconnectAttempt等钩子接入 UI 提示节流联动若你的页面处理器非常耗时客户端会自动要求服务器降速无需手动干预默认策略以 500ms 为基准步进调整API Key 场景仅配置apikey的客户端需依赖passiveLogin()取得会话后才能完成 Socket 认证消息类型扩展插件可以通过octoprint.server.sockjs.emit等钩子扩展推送内容客户端侧用onMessage(plugin, ...)即可接收插件消息具体载荷结构由插件定义。通过本文所述选项、方法与节流原理你已具备在自有 Web 界面或第三方客户端中复用 OctoPrint 实时通信通道的完整能力结合 docs/api/push.rst 中的消息数据模型定义即可进一步定制具体的推送内容解析与 UI 响应逻辑。赞分享物联网后端【免费下载链接】OctoPrintOctoPrint is the snappy web interface for your 3D printer!项目地址https://gitcode.com/gh_mirrors/oc/OctoPrint点击查看免费下载相关推荐sockjs-client消息确认机制实现可靠的实时通信sockjs client消息确认机制实现可靠的实时通信 在实时Web应用开发中你是否遇到过消息发送后石沉大海的情况用户点击提交按钮却看不到反馈客服消息即时通讯Sails io.socket 详解浏览器端实时通信 Socket 客户端全局实例完全指南Sails io.socket 详解浏览器端实时通信 Socket 客户端全局实例完全指南 导读 io.socket 是 Sails 实时 MVC 框架 s后端Yep实时通信FayeService消息订阅系统原理分析Yep实时通信FayeService消息订阅系统原理分析 Yep项目的FayeService实时通信系统基于Bayeux协议通过WebSocket技术实现了社交上一篇Nazara Engine着色器编程完全指南NZSL语言从入门到精通下一篇终极指南如何使用Node-Express-Boilerplate快速构建企业级RESTful API创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表