news 2026/7/27 7:14:30

第06篇_Server 02|监听端口以后,PLC 为什么还没有收到请求

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第06篇_Server 02|监听端口以后,PLC 为什么还没有收到请求

适合谁收藏

  • 正在实现 PLC 端 HTTP Server 的工程师。
  • 正在排查监听、多连接、请求边界或响应发送问题的人。
  • 需要建立 Server 真机验收清单的读者。

本篇位置服务器篇,第 2/7 篇;主系列第 06/28 篇。

现场问题

调试 PLC Server 时,经常先看到端口 8088 已经可以连接,于是开始在业务代码里查为什么没有路径和 Body。问题通常不在业务层,而在监听句柄之后还有一条没有走完的链。

NBS.TCP_Server负责监听,NBS.TCP_Connection负责接入。只有接入句柄绑定到一个 HTTP 连接槽位,并且该槽位持续执行 Read,协议层才可能获得完整请求。

先给结论

Server 的第一条验收线不是“端口能连”,而是“监听句柄有效、连接槽位激活、请求进入解析器、响应可以返回”。四个状态缺一个都不能宣布跑通。

读图重点

这张图只压缩本篇的判断路径。读图时先找“Disabled”对应的输入边界,再沿着“接入并服务所有槽位”检查状态怎样推进,最后用“聚合请求和错误”确认输出是否已经形成验收证据。

把对象和边界分开

对象或阶段工程职责现场观察点
Disabled未使能或已复位监听句柄必须为 0
Init清理历史错误与句柄准备进入 Listen
Listen周期调用 TCP_Server等待有效 hServer
Running接入并服务所有槽位聚合请求和错误

从协议约束到代码职责

协议约束

Server 的第一条验收线不是“端口能连”,而是“监听句柄有效、连接槽位激活、请求进入解析器、响应可以返回”。四个状态缺一个都不能宣布跑通。 这条结论先限定消息什么时候成立,再限定哪个角色可以消费结果。若绕过协议边界直接驱动业务,半包、超时、重复执行和连接残留就会进入应用层。

工程抽象

Server 外层状态机只管理监听和槽位调度。单连接收发交给FB_HttpServerConnection,这避免一个连接的半包或错误阻塞其他连接。

监听状态必须对外暴露xListeningbListeninghListenHandle。现场如果只给一个bError,就无法判断故障发生在监听、接入还是 HTTP 解析阶段。

  • Disabled:工程职责是“未使能或已复位”。它不能只停留在命名层面,运行时必须能通过“监听句柄必须为 0”观察到输入、状态或结果;否则这一层即使有代码,也没有形成可验证边界。
  • Init:工程职责是“清理历史错误与句柄”。它不能只停留在命名层面,运行时必须能通过“准备进入 Listen”观察到输入、状态或结果;否则这一层即使有代码,也没有形成可验证边界。
  • Listen:工程职责是“周期调用 TCP_Server”。它不能只停留在命名层面,运行时必须能通过“等待有效 hServer”观察到输入、状态或结果;否则这一层即使有代码,也没有形成可验证边界。
  • Running:工程职责是“接入并服务所有槽位”。它不能只停留在命名层面,运行时必须能通过“聚合请求和错误”观察到输入、状态或结果;否则这一层即使有代码,也没有形成可验证边界。

程序单元

本篇主证据来自FB_HttpServer.st中以CASE eState OF为定位点的连续源码。这里不是为了展示语法,而是把协议约束落到确定程序单元:输入先进入结构体或缓冲区,状态机只在本周期处理可确认的部分,长度和结束条件决定能否前进,错误码与指标负责把失败原因带出对象边界。这样一来,“监听、接入和 HTTP 请求是三个不同事件。”可以在代码、在线变量和外部报文之间逐项对照,而不是依赖经验猜测。

本篇核心源码片段

下面两段代码来自同一个真实文件FB_HttpServer.st,以CASE eState OF为中心连续截取,没有改写变量、删除分支或用伪代码替代。第一段用于确认入口与前置条件,第二段用于确认状态、边界和输出。核对时重点看“未使能或已复位”怎样进入对象,以及“聚合请求和错误”怎样证明本次处理已经结束。若两段之间的连续关系无法解释“端口检查必须继续追到请求和响应证据。”,就不能把局部代码截图当成实现证据。

片段一:入口、声明与前置条件

udiNowMs := udiNowMs ); aConnectionSnapshots[uiSlotIndex] := aConnections[uiSlotIndex].stConnection; END_FOR M_Reset(); RETURN; END_IF CASE eState OF E_HttpServerState.iDisabled: eState := E_HttpServerState.iInit; E_HttpServerState.iInit: hServer := 0; hListenHandle := 0; bError := FALSE; eLastError := E_HttpError.iNoError; sDiagMsg := ''; eState := E_HttpServerState.iListen; E_HttpServerState.iListen, E_HttpServerState.iRunning: fbServer( xEnable := TRUE, ipAddr := ipBindAddr, uiPort := uiPort, eError => eTcpError ); hServer := fbServer.hServer; hListenHandle := hServer; IF fbServer.xError THEN eLastNbsError := eTcpError; M_SetServerError( eError := E_HttpError.iTcpServerFailed, sMessage := 'TCP server listen failed' ); eState := E_HttpServerState.iFault; ELSIF hServer <> 0 THEN eState := E_HttpServerState.iRunning;

这一段先回答对象在什么输入和状态下开始工作。阅读时要核对变量的初值、长度上限和启动条件,不能只看某个布尔量是否变成 TRUE。

片段二:状态推进、边界与输出

M_AcceptNewConnection(); M_ServiceConnections(); END_IF E_HttpServerState.iFault: fbServer( xEnable := FALSE, ipAddr := ipBindAddr, uiPort := uiPort ); ELSE eState := E_HttpServerState.iFault; END_CASE M_UpdateServerOutputs(); // === METHOD M_AcceptNewConnection === /// ======================================================================= /// 名称 : M_AcceptNewConnection /// 功能 : 周期调用所有 NBS.TCP_Connection 接入槽位。 /// 说明 : 所有槽位每周期都调用,符合 NBS 电平触发语义。 /// ======================================================================= {attribute 'hide_all_locals'} METHOD PRIVATE M_AcceptNewConnection // === IMPLEMENTATION === // 工程说明:本段集中处理状态、边界或诊断,避免跨周期残留。 // 边界说明:执行前后保持输出和错误码可被在线诊断追踪。 bAcceptError := FALSE; FOR uiSlotIndex := 1 TO GVL_Http.cnMaxClientSlots DO aTcpAccept[uiSlotIndex]( xEnable := hServer <> 0, hServer := hServer ); IF aTcpAccept[uiSlotIndex].xActive THEN IF (NOT aConnections[uiSlotIndex].bActive) OR (aConnections[uiSlotIndex].stConnection.hConnection <> aTcpAccept[uiSlotIndex].hConnection) THEN // 原因:接入阶段只绑定 NBS 句柄,读写统一留给 M_ServiceConnections; // 避免新连接在同一扫描周期被 TCP_Read 调用两次,导致大 body 半包场景被误判为接收错误。 aConnections[uiSlotIndex].M_Attach(

第二段继续展示同一连续源码范围。把它与第一段合起来,才能判断输入怎样被锁存、状态何时推进、边界何时满足,以及错误出口是否保留了足够诊断信息。

验证路径

场景操作通过口径
监听hListenHandle 非 0,状态为 Running证明端口由 PLC 持有
接入AcceptedConnections 递增证明外部连接进入槽位
请求uiLastRequestSlot 和目标路径更新证明 HTTP 请求完成
响应外部工具获得合法响应证明事务闭环

场景 1:监听

启动 Server 后检查hListenHandle非 0、状态为 Running,并用外部工具确认目标端口可以建立 TCP 连接。这一步只证明端口由 PLC 持有,不代表连接已经进入 HTTP 连接槽,更不代表请求已经解析完成。

场景 2:接入

保持连接但暂不发送完整请求,观察AcceptedConnections、活动连接数和槽位快照。计数递增且某个槽位进入接收态,才说明 Accept 结果已经交给连接实例。如果端口能连但这些量不变化,应查接入调度,不要先改 Parser。

场景 3:请求

发送一条完整请求后,uiLastRequestSlot应指向实际处理槽位,最近目标路径应与请求行一致,接收缓冲的完成边界应由 Parser 给出。只有这三项同时成立,才可以把请求交给路由;仅看到 Read 返回字节数还不算收到 HTTP 请求。

场景 4:响应

最后核对外部工具收到的状态行、Header 和 Body,并观察发送状态退出、连接按策略关闭或回到可复用态。外部响应正确但槽位一直占用,说明事务只完成了报文发送,没有完成资源回收;这种状态不能算 Server 跑通。

常见误判

  • 看到 hListenHandle 非零就宣布 Server 已经收到 HTTP 请求。
  • 监听失败、接入失败和协议解析失败只共用一个模糊错误码。
  • 新连接接入后没有持续服务连接槽,句柄存在但请求永远不推进。

这些误判的共同点,是拿一个局部现象替代完整事务。定位时必须回到本篇的输入、状态、边界和输出四个坐标,并用相同输入完成回归。

这一篇你最该记住

  • 监听、接入和 HTTP 请求是三个不同事件。
  • Server 外层只做生命周期和调度。
  • 端口检查必须继续追到请求和响应证据。

系列导航

  • 系列:CodeSys HTTP 系列教程,第 06/28 篇。
  • 阶段:服务器篇,职责线位置 2/7。
  • 上一篇:第05篇
  • 下一篇:第07篇
  • 发布顺序:基础认知 -> Server -> Client -> 完整源码加更 -> 综合收束。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/27 7:11:04

C++标准库实战指南:从原理到应用,提升开发效率

1. 项目概述&#xff1a;为什么我们需要一本C库函数实战手册&#xff1f;如果你是一名C开发者&#xff0c;无论是刚入门的新手&#xff0c;还是摸爬滚打多年的老手&#xff0c;相信都曾有过这样的经历&#xff1a;面对一个看似简单的功能&#xff0c;却要花上半天时间去翻阅浩如…

作者头像 李华
网站建设 2026/7/27 7:10:43

Langfuse开源LLM工程平台:架构解析与应用实践

1. Langfuse&#xff1a;开源LLM工程平台全景解读在大型语言模型&#xff08;LLM&#xff09;应用开发领域&#xff0c;工程化落地一直是困扰开发者的难题。Langfuse作为新兴的开源LLM工程平台&#xff0c;正在改变这一现状。这个项目最初由德国柏林的技术团队在2023年推出&…

作者头像 李华
网站建设 2026/7/27 7:09:01

嵌入式实时系统流I/O:SIO模块原理、API与实战指南

1. 流I/O在嵌入式实时系统中的核心价值在嵌入式实时系统里&#xff0c;尤其是像TI C6000系列DSP这种处理密集型数据流的场景&#xff0c;数据搬运的效率直接决定了整个系统的性能天花板。你想想看&#xff0c;一个音频编解码器&#xff0c;或者一个视频采集卡&#xff0c;数据像…

作者头像 李华
网站建设 2026/7/27 7:06:30

在线教育评估模型:从数据采集到机器学习实践

1. 在线教育评估模型的背景与挑战在线教育行业近年来呈现爆发式增长&#xff0c;根据最新统计数据显示&#xff0c;2023年全球在线教育市场规模已突破3500亿美元。在这个快速发展的背景下&#xff0c;如何科学评估学习效果成为行业痛点。传统评估方式主要依赖考试成绩和作业完成…

作者头像 李华
网站建设 2026/7/27 7:04:50

C语言环境安装---visualstudio(Windows版)

1——下载 打开visualstudio官网 https://visualstudio.microsoft.com/zh-hans/downloads/ 普通用户下载社区版即可&#xff0c;其他按需下载 2——安装 打开安装包进行安装 C语言环境可以勾选这个选项 接下来可以选择安装路径 C盘空间不足的&#xff0c;可以换到其他盘 更改完…

作者头像 李华
网站建设 2026/7/27 7:03:33

第6章 无监督学习:没有标准答案怎么办

第6章 无监督学习&#xff1a;没有标准答案怎么办一句话点题&#xff1a; 监督学习是"做题对答案"&#xff0c;无监督学习是"发一堆混在一起的扑克牌&#xff0c;没人告诉你怎么分&#xff0c;你自己整理"。没有标准答案&#xff0c;但机器照样能找出规律来…

作者头像 李华