1. 从一台设备重启开始的“全站轮询停滞”
1.1 现象:Modbus Poll读得好好的,PLC就是读不到
去年我接过一个项目,现场是S7-1200通过Modbus TCP轮询4台从站设备,设备端是温控器、变频器和一台小型仪表,IP地址分配得很规矩,网段、端口、寄存器表都清清楚楚。程序写完后,单台调试、四台联调都通过了,数据刷新也稳定,我当时觉得这个项目稳了。
结果没过多久,现场反馈了一个特别诡异的现象:3号温控器因为供电回路跳闸突然断电,送电重启之后,整个系统的4台从站全部读不回来。而且不是读一次超时、下次自愈那种,是一直读不回来,直到把PLC也断电重启,系统才恢复正常。
我赶到现场,第一反应是轮询逻辑写串了,或者从站重启后IP地址变了。但打开电脑上的Modbus Poll,填上IP地址、端口502、功能码03,一路读过去,每个寄存器清清楚楚,数据完全正常。也就是说,同一台交换机、同一台设备、同一个IP,调试软件能读,PLC读不回来。
这种“软件正常、PLC异常”的现象,在Modbus TCP项目里其实比很多人想象的更常见。我花了一整天,换过轮询周期、换过超时时间、改过寄存器地址映射,全部没用。最后把Wireshark挂上抓包,看着报文才明白,问题根本不在Modbus的应用层,而藏在了TCP的连接层。这个坑不是改几个地址参数能绕开的,它直指Modbus TCP整个协议栈在工业现场使用时的结构性弱点。
1.2 第一轮排查:字节序、寄存器地址、功能码都试过
那次现场排查,其实把我所有“常规武器”都打光了。
先检查了IP和端口配置。4台从站的IP我都重新ping过,通,没有冲突。接着查寄存器地址映射,拿PLC里读回来的原始值和Modbus Poll的读值做对比,发现根本不是偏移量的问题——因为PLC那边连一个正常响应都拿不到,不是“数据值不对”,是“没有响应”。再查功能码,文档上说3号温控器的温度寄存器是03功能码的保持寄存器,我用Modbus Poll验证过,同一功能码没有问题。
然后我开始怀疑轮询节奏。S7-1200这边我用了一个MB_CLIENT块,顺序轮询4台设备,每台之间留了50ms间隔,请求超时设置500ms。当时怀疑是不是请求间隔太短,导致从站处理不过来。把间隔从50ms加到了300ms,结果没用;又把超时从500ms加到2000ms,还是没用。
最后把电脑的防火墙关掉、交换机端口重启、PLC程序重新下载,统统试了一遍,故障依旧。唯一有效的手段就是把PLC断电重启——这也是现场操作的“终极办法”,但只要再重复一次“3号从站断电重启”,故障就会再次出现。
这个“稳定复现”的规律其实已经给了我很大提示:问题一定和3号从站的TCP连接状态有关。但在当时,我对Modbus TCP的理解还停留在“IP+端口+寄存器地址”这个层面,没有意识到连接层状态的破坏,会直接让整个应用层的轮询全部失效。这篇博文想聊的,就是我把这个坑彻底刨开后的完整认识。
2. 表面坑排雷:这些坑够常见,但都算不上“最深”
2.1 字节序/字序错乱:同一个地址,四种不同的解释
Modbus协议本身传输的是16位寄存器,数据以大端字节序排列,也就是一个寄存器里高字节在前、低字节在后。这个规则本身不算复杂,复杂的是寄存器数据跨两个16位时的排列方式,比如32位浮点数。
不同厂商的设备,存储一个32位浮点值时,可能是“寄存器顺序正序、寄存器内字节大端”,也可能是“寄存器顺序正序、寄存器内字节小端”,甚至可能“寄存器顺序反序但字节序正常”,一共存在四种排列。大部分新手看到读回来的数据是零或者一个天文数字,第一反应就是公式算错了,其实是字节序没对上。
举个例子,一个温度值100.5,按IEEE754浮点数存成32位,拆成两个寄存器后,有的设备里存成:
- 第一寄存器:0x42C9,第二寄存器:0x0000
- 有的设备则存成:第一寄存器0x0000,第二寄存器0x42C9
- 还有的在寄存器内部把高低字节交换
在S7-1200里,MB_CLIENT读回来的原始数据直接就进到DB块,你需要根据从站文档或者实测结果,用字交换、字节交换指令把数据调整成程序能直接用的人性化数据。这个坑好解决,因为拿Modbus Poll或者直接看原始寄存器值就能对比出来,属于“半小时能定位”的范畴。
2.2 寄存器地址偏移:文档地址与协议地址永远差的那个“1”
字节序坑后面还有一个隐藏很深的细节,就是地址偏移。
很多设备的寄存器手册,习惯用“40001、40002”这种PLC风格的地址来描述,第一个保持寄存器叫40001。但Modbus TCP协议报文里,功能码03后面跟的起始地址是从0开始的,也就是说,手册上的40001对应协议地址0,40002对应协议地址1。
如果你直接把手册上的40001填进上位机或者PLC的起始地址参数里,读回来的是第二个寄存器。少数现场设备就差这1个寄存器,导致温度、压力、频率全部错位,换算出来完全不是现场值。更麻烦的是,有些工具在界面上能切换“PLC地址”和“协议地址”两种显示模式,配置的时候混用了,排查起来很容易绕晕。
S7-1200的MB_CLIENT指令,DATA_ADDR参数用的是协议地址,不是PLC地址,这个在官方帮助文档里有写,但现场很多人第一遍都不会细看。好在这种坑同样不影响连接,只影响数据内容,抓包对比请求报文和响应报文就能确认。
2.3 功能码和寄存器类型混用:03、04、01、02的语义差异
Modbus TCP的功能码我列一下最常见的几个:
| 功能码 | 含义 | 访问类型 |
|---|---|---|
| 01 | 读线圈 | 位,读写 |
| 02 | 读离散输入 | 位,只读 |
| 03 | 读保持寄存器 | 字,读写 |
| 04 | 读输入寄存器 | 字,只读 |
| 05 | 写单个线圈 | 位 |
| 06 | 写单个寄存器 | 字 |
| 15 | 写多个线圈 | 位 |
| 16 | 写多个寄存器 | 字 |
03和04是最容易混的。有的设备手册上只写“寄存器号”,不区分用途,再加上部分设备把只读参数放在输入寄存器里,把可写参数放在保持寄存器里,你一旦用错了功能码,请求会成功返回,但返回的值可能恒为0或者完全对不上。更迷惑的是,有些设备对不存在的功能码会回异常,有些则把所有功能码都当作03处理,这就更坑了。
我的经验是,接到一个新设备后,先用Modbus Poll把03、04、01、02各扫一遍,确认哪些地址有数据、哪些报异常,再据此确定PLC里的功能码配置。别依赖厂家文档上的“寄存器表”去做一字不差的翻译,文档经常滞后于固件版本。
2.4 把“轮询间隔”当成“从站响应时间”的偏差
设备通信正常后,还有一类表面坑和时序有关。
串行轮询有一个基础约束:同一时刻只能有一个请求在等响应。所以你的轮询周期不是“每台设备响应时间之和”,而是“每台设备响应时间之和加上可能发生的超时时间之和”。这个公式我在第4部分会详细展开,这里先提一个容易误解的点:很多人把Modbus Poll里的轮询间隔设置当成从站的响应时间参考,这是不对的。
Modbus Poll在PC上跑的时候,间隔设小一点,比如10ms,通常也能正常读,但这不代表PLC用10ms间隔也正常。从站的响应速度受其CPU负载、通信任务调度、TCP栈处理能力影响,PC的协议栈处理线程和PLC的任务周期完全不是一回事。我自己就见过一台变频器,Modbus Poll用20ms间隔能连续读几百次不报错,但S7-1200用100ms轮询周期却时不时超时,最后发现是变频器的通信任务优先级设计问题,响应时间存在明显的最大抖动。要拿到可靠的轮询周期基准,只能实测从站的极端响应时间,不能拿调试软件的手感来替代。
3. TCP半死连接:Modbus TCP最深、最隐蔽的陷阱
3.1 为什么Modbus TCP比Modbus RTU多出一个“连接维度”
前面说的这些坑,本质上都是“数据解读”和“参数配置”层面的问题,哪怕全踩一遍,也只要对照工具逐项排除就行。真正让我觉得Modbus TCP“藏得最深”的坑,是TCP连接本身的状态失效问题。
做Modbus RTU的时候,一条485总线,主站发请求,从站回响应,一个请求一个应答,没有“连接”这个概念。从站掉电重启、总线干扰、拔线插线,都不影响下一次请求重发。主站不关心对方什么时候在线,只要发出请求后能等到响应就行。
但Modbus TCP不同,它把TCP协议作为承载层,而TCP是一种面向连接的、有状态的传输协议。连接意味着通信双方在内核里维护了一套状态信息:对方的IP、端口、序列号、确认号、发送窗口、接收缓冲等等。连接建立后,你的每一次“发请求”,实际上都是在一个既有连接上发送报文。
问题是,Modbus TCP的应用层完全没有定义任何形式的“心跳”或“保活”机制。请求来了就处理,响应回完就继续等下一个请求。如果一端悄无声息地消失——比如设备断电,另一端在短时间内根本感知不到。这才是所有“神秘故障”的根源。
你可以把半死连接想象成打电话:A和B正在通话,B那边突然断线、把电话扔在桌上走了,但A手里的线路还是“通话中”状态。A继续对着话筒说话,B听不到,B也不会回话,A就这么对着一个死连接自言自语。Modbus TCP现场最经典的故障画面,就是这种“电信级”的死连接。
3.2 半死连接的现场全过程:设备重启 → 请求黑洞 → 超时重传
我复盘一下3号温控器那次故障的完整技术过程。
3号温控器断电瞬间,S7-1200与它之间的TCP连接,在S7-1200这一端还保持着“已建立”状态。设备重启后,温控器的TCP协议栈初始化,它自己完全不记得这个旧连接,也不会主动通知PLC“我重生了”。此时S7-1200继续通过旧连接发送Modbus请求,这些请求到达温控器后,温控器发现这是一个自己根本不知道的TCP连接,于是按照TCP协议,发送一个RST(重置)报文,试图把这条连接打断。
正常情况下,这个RST会让S7-1200感知到“连接被重置”,从而触发错误处理。但问题就在于,现场网络环境不可能像实验室那么干净。交换机的缓存、防火墙策略、链路拥塞,或者从站侧TCP栈的异常实现,都可能导致RST报文没有及时送达,甚至被丢弃。S7-1200不知道连接已死,只能继续在旧连接上发送请求,每一个请求都因为没有响应而触发TCP层的重传机制。
TCP重传有一个自适应超时算法,根据历史往返时间来估计重传间隔。如果之前通信一直很顺畅,往返时间很短,那么初始重传间隔会非常小,但重传次数多了,超时时间会按指数退避递增。表现到现场就是:第一个请求在500ms的Modbus超时后报错,第二个请求可能要等1秒,第三个可能要等2秒,越拖越长。
你明明把Modbus请求超时设成了500ms,但实际一个轮询周期下来,可能已经在TCP重传层耗掉了几秒钟。更糟的是,如果你的程序在Modbus超时后立即重试,下一个请求又发到同一个死连接上,TCP层可能还在等前面那个报文的重传确认,新报文只能排在发送缓冲里。请求越积越多,整个轮询就彻底冻结了。
3.3 Wireshark里能看到但从不被留意的RST包
那次现场抓到包后,现象非常清晰。
我用Wireshark挂在电脑上,过滤器写的是tcp.port == 502,看到S7-1200反复向3号温控器发送Modbus请求报文,但响应报文一个都没有。真正让我确定问题根源的,是3号温控器断电重启后出现的几个RST报文。
其实RST在很多Modbus TCP现场里都会出现,但绝大多数人抓包时根本不会注意。一个RST报文,看起来不像正常的Modbus事务,Wireshark默认视图里会把它标成红色,但它不携带任何应用层数据,很容易被当作“底层杂音”忽略过去。可就是这个RST,揭示了“旧连接已经失效”的全部真相。
排查时还有第二个细节值得注意:看TCP重传标志。Wireshark里如果出现大量的TCP Retransmission或者TCP Fast Retransmission,而且这些报文都是同一个连接的,那基本可以断定这条连接已经半死了。Modbus TCP的请求报文本身很小,可能只有12个字节左右,在Wireshark里一排排红色重传报文刷屏,就是一个很直观的“半死连接”特征。
我当时看到的现象是:4台从站的Modbus请求全部发到各自独立的连接上,3号温控器这条连接上全是重传和RST,而另外3台从站的请求全都正常发出但得不到响应,因为整个轮询循环已经被3号温控器卡死了——它不返回错误,也不返回数据,PLC逻辑永远在等它超时。
3.4 S7-1200的MB_CLIENT为什么特别容易踩中“半死连接”
S7-1200的MB_CLIENT指令有几个使用习惯,会让“半死连接”的影响放大到整个轮询系统。
第一个习惯是让CONNECT信号长期保持TRUE。MB_CLIENT在CONNECT为TRUE的情况下会建立并维持连接,这是标准用法。但问题在于,很多程序里CONNECT接的是一个常ON位,从站重启后,S7-1200不会主动尝试新建连接,它只会在旧连接上继续发请求,每次都超时、每次都失败,而MB_CLIENT又不负责重连,于是这个从站就被永久卡死。
第二个习惯是REQ信号被固定成常TRUE或者上升沿处理不严谨。MB_CLIENT的要求是REQ有上升沿时才触发一次请求,如果REQ一直被置位,请求会一个接一个地往外发,根本不等待前一个事务结束。这种写法在半死连接状态下尤其致命,因为它会以极快的速度把一个已经失效的连接填满重传队列,让TCP层更加混乱。
第三个习惯是错误处理后没有“强制拆链”的步骤。很多人遇到MB_CLIENT的ERROR位为TRUE,只是做一个故障标志,清了之后重新触发REQ,试图再读一次。但连接本身已经处于半死状态,单纯的“重发请求”没有任何意义,正确做法是先让CONNECT变FALSE,等连接彻底断开,再置TRUE重建连接。
这三个习惯叠加在一起,就构成了现场最典型的一个故障场景:从站重启一次,整个轮询系统跟着瘫痪,直到PLC断电重启。
4. 四台从站轮询的串行陷阱:一个站故障拖死所有站
4.1 串行轮询的时间预算:不是每台100ms,而是“超时叠加”
用一台S7-1200轮询4台从站,最直观的写法是写一个循环:先查1号、再查2号、再查3号、最后查4号,每一台等待完成或超时后,再进下一台。这种写法节省了通信资源,但也把所有的延时风险全部串在了一起。
我来算一笔时间账。假设每台从站正常响应时间是100ms,4台加起来是400ms,一个轮询周期大概半秒,听起来很不错。但你需要额外考虑每个从站的异常状态:如果1号从站掉线,你的Modbus请求要等多久才能拿到错误?如果你设置了500ms请求超时,那么1号从站就要白等500ms;如果TCP半死连接还在重传,实际等待时间可能翻倍。
轮询周期的真实公式是:
轮询周期 = 各站正常响应时间之和 + 所有故障站的请求超时时间之和假设4台中有一台掉线,且掉线站的请求超时是1000ms,那么完整轮询周期就变成3×100ms + 1000ms = 1300ms,比原来慢了一倍多。如果这台掉线站触发了TCP重传,实际耗时可能从1000ms膨胀到3000ms以上,整个系统的刷新率烂到无法接受。这还没算上PLC任务扫描周期的叠加效应。
所以,设计轮询时第一件事就是给每个从站设置“独立的事务超时”,并且这个超时不能太长。500ms的请求超时对大多数从站都够用,但一定要确认它真的在500ms时放弃当前请求,而不是被TCP重传机制拖着走。
4.2 TCP重传与事务ID冲突:响应比请求晚到的后果
四台轮询还有一个隐蔽的问题,和Modbus TCP协议头里的“事务ID”有关。
每个Modbus TCP请求报文都有一个事务ID,用来把请求和响应配对。主站发一个事务ID为0x0001的请求,从站响应时也会带着0x0001。正常通信时,一应一答,很好对应。
但半死连接场景下,情况会变得非常混乱。TCP层在旧连接上重传一个请求,这个请求如果迟迟没有响应,应用层可能已经超时并转为“重连”状态。重连成功后,你又发了一个新请求,事务ID可能是0x0002。这时候,如果旧连接上的响应终于到达了——比如设备重新上电后终于把这个旧连接的残留报文处理了——响应带的事务ID是0x0001,主站的协议栈如果还守着0x0002的事务ID,这个0x0001的响应就会被当作无效帧丢弃。
这种“迟到的响应”造成的偶发超时,在四台从站轮询时尤其阴魂不散。因为它不是每次都出现,而是只在“设备重启 + 旧连接重传 + 新连接建立”这个特定窗口里出现,排查时极其难复现。
4.3 现场事故复盘:1号机断电,2、3、4号机全部超时的真正原因
回到那个项目现场,把抓包数据捋一遍,真相其实非常符合刚才的分析。
3号温控器断电那会儿,S7-1200的MB_CLIENT正轮询到3号。PLC发了一个读请求,事务ID是0x0023,没响应。TCP层开始重传,Modbus层的请求超时500ms到了,MB_CLIENT返回ERROR,程序根据常规逻辑往下走到4号从站,把请求发出去。
但4号从站的响应其实很快就到了,问题是4号的响应报文可能被3号“迟到的重传风暴”挤占,或者说等到PLC轮询到4号时,程序内部还在处理上一轮的异常状态,没有及时转换到4号的事务ID上。更简单的解释是:程序轮询到4号时,发现4号的数据也没刷新,因为前一轮3号超时没有完成,程序通过一个共同的状态位让整个轮询序列都停住了。
我以前很不理解为什么一个从站故障能拖死整条轮询链,直到亲手调过这种“串行依赖”逻辑后才明白:问题往往不是PLC真的收不到其他从站的数据,而是程序把“前一站超时”当成了“整个轮询序列失败”的充分条件,无条件中断了后续请求。这种设计在Modbus RTU时代影响不大,因为RTU主站的重试机制很简短,但在Modbus TCP的半死连接面前,一次超时很容易膨胀成长期瘫痪。
5. 根源解决:给Modbus TCP轮询补上真正的重连机制
5.1 用状态机管理连接:连接检测、断点重建、请求串行
认清半死连接的机制后,解决方案其实已经摆在眼前:不要“信任”TCP连接,把“连接检查”和“断线重连”当作Modbus TCP应用的一部分。
我现在的标准做法是,把每个从站的轮询流程拆成几步,用程序里的状态来表示:
- 第一步,检查连接是否建立。如果连接没建立,置CONNECT为TRUE,等待连接成功,再发请求。
- 第二步,连接建立后,触发请求,等待响应或等待超时。
- 第三步,如果请求超时,不直接重复触发请求,而是先把连接断开:置CONNECT为FALSE,等待一个断开确认周期,再重新置TRUE。
- 第四步,连接重建后,再从第一步开始。
这个流程的关键点,是“断开重建”必须比“重发请求”优先。很多程序为什么会反复超时?因为它在半死连接上不断重试,重试一万次也没用,重试次数的增加只是在加剧TCP层的重传堆积。
有些工程师觉得每次超时后断开重连太繁琐,会让通信变慢。其实不然。对于正常的从站,一年都难得出现一次超时;对于真正掉线的从站,你断掉旧连接、重新建立新连接,最多耗时几十毫秒到几百毫秒,远远小于你在半死连接上空转几十秒的代价。
5.2 用S7-1200实现4台轮询的方案选型(单MB_CLIENT与每台独立MB_CLIENT)
具体到S7-1200,轮询4台从站通常有两种架构,各有适用场景。
第一种是单MB_CLIENT顺序轮询。一个MB_CLIENT实例,程序里轮流把4台从站的IP、端口填到ADR参数中。这种方案的优点是占用的程序空间少、通信带宽好控制,但缺点是每切换一个从站,都需要先断开旧连接、再建立新连接。因为MB_CLIENT在连接建立后修改ADR参数并不安全,通常必须把CONNECT拉低再拉高,等待连接状态稳定后再发请求。连接断开和重建需要时间,所以4台轮流下来,会有一半左右的时间耗在连接切换上。
第二种是每台从站一个MB_CLIENT实例。程序里建4个MB_CLIENT块,每个块固定对应一台从站的IP和端口,大家各自独立维护连接。这种方案的优点是连接不切换,轮询速度快,程序逻辑更直观;缺点是每个从站都会保持一个长期连接的TCP资源,如果你的从站设备TCP栈很简陋,比如只允许一个客户端连接,那另一个调试软件一旦连上它,PLC这边就会被踢掉线。
对“4台Modbus TCP轮询”这个典型需求,如果从站设备本身没有“单连接”限制,我更推荐每台独立MB_CLIENT。4个连接并不多,S7-1200完全扛得住,而且把每个从站的轮询隔离成独立状态机,一个从站掉线不会拖死其他从站。
如果从站设备明确限制连接数只有1个,那就只能接受单MB_CLIENT轮询,但需要把连接切换逻辑写正确:
- 先记录当前从站索引。
- 对当前从站发请求,等待超时或响应。
- 完成之后,将CONNECT置为FALSE,等待一个扫描周期或一个50ms定时器。
- 切换索引,修改ADR参数,将CONNECT置为TRUE,等待“连接已建立”。
- 再触发REQ请求。
这个过程中最忌讳的就是在CONNECT保持TRUE的情况下直接改ADR去连下一台,很多“轮询第二轮就断线”的故障就是这么来的。
5.3 把断电重启纳入出厂测试:轮询程序的验收标准
还有一个我后来越来越坚持的验收标准:每一套写好的Modbus TCP轮询程序,都必须通过一轮“暴力测试”。
测试方法很简单,在现场投运之前,把每一台从站依次断电重启,观察PLC这套轮询系统能否在短时间内自动恢复。具体标准是:
- 单台从站断电10秒后重启,系统最多在30秒内恢复对该从站的数据读取。
- 单台从站长期断电,另外几台从站的轮询周期不能明显劣化。
- 全部从站断电后同时恢复,系统能在1分钟内自动恢复到稳定轮询状态。
这套测试能非常有效地暴露“半死连接”相关的各类Bug。很多时候,开发阶段用Modbus Poll调试一切正常,因为Modbus Poll会在连接断开后自动重连,过程完全透明,掩盖了TCP层的问题。而PLC程序里如果不做断线重建,一测必翻车。
我自己吃过的亏就是当年没做这个测试,到现场才踩进深坑。现在不管是西门子、三菱还是其他支持Modbus TCP的PLC,只要是我手写的轮询逻辑,这套暴力测试都是必过项。
6. 事后总结:我后来是怎么避免再踩这个坑的
6.1 三条我用得最多的经验
第一条经验:永远不要假设TCP连接是“可靠长连接”。Modbus TCP的承载层是TCP,但TCP连接本身不保证永远有效。设备重启、网络拔插、交换机级联切换,都可能让连接变得半死。你的轮询程序必须默认“连接随时会断”,才能写出真正能自愈的逻辑。
第二条经验:让步Modbus TCP轮询程序的错误处理机制里,把“断线重建”当作一个独立、显式的环节,而不是把重发请求当成万能解法。重发请求只适合“丢包”场景,不适合“连接失效”场景。连接失效时,唯一的自愈路径就是断开、重连、再发请求。
第三条经验:把轮询系统的故障隔离做好。一台从站的故障不能影响其他从站。在程序设计时,给每个从站分配一个独立的状态记录区,一台超时了,只标记这一台故障,下一轮还是按时去轮询其他从站,只是故障站的重试频率可以适当降低。不要因为某台从站连着超时几次就把整个轮询循环停下来。
6.2 诊断工具箱:抓包、连接数、停机测试
最后分享几个排查工具,大家遇到类似问题可以直接照做。
抓包是最直接的手段。Wireshark过滤器用tcp.port == 502,重点关注三类报文:RST报文、TCP重传报文、ACK异常。如果看到某个连接上不停有重传,却没有任何Modbus响应,那基本可以锁定半死连接。
连接数检查也值得做。很多低端从站设备只允许建立1到2个TCP连接,PLC占了一个连接,调试软件再连一个,第三个连接就会被拒绝。有些“轮询偶尔超时然后自己恢复”的奇怪问题,其实是上位机软件不定期抢占连接导致的。遇到这种从站,记住一条原则:调试时用完Modbus Poll就断开,别一直挂着。
停机测试就是5.3说的暴力测试,这里再强调一遍。每台从站都要做“运行中断电重启”试验,而且要在轮询系统稳定运行一段时间后做,不是刚上电通信成功就完事。因为半死连接的问题往往在运行一段时间后才暴露,刚上电时所有连接都是新建的,看不出问题。
做这个测试时,我会在PLC程序里记录每个从站“连续超时次数”和“最近一次重连时间”,恢复后从数据里就能清楚看到,从站重启后多久被重新纳入轮询周期。这个数据也是给甲方验收时最有说服力的交付物。
我也补充一点经验:Modbus TCP这个协议并非不成熟,恰恰因为太简单,很多工程师从一开始就只盯着“发送请求、接收响应”这个应用视角,忽略了TCP连接状态的管理才是真正决定系统可用性的部分。把这个视角补齐,Modbus TCP其实可以做得非常稳定。我在后来的几个项目里,都按这套重连机制做,从站断电重启再也没成为过系统级故障。