You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Wago PFC200控制器通过MQTT_Client库连接MQTT Broker时TCP连接超时故障排查咨询

排查Wago PFC200 MQTT连接超时(SysSockConnect失败)的思路

看起来你已经做了不少基础排查,但还是卡在TCP连接这一步——既然Socket能创建成功,问题大概率出在地址解析、网络通路或者Socket配置上,结合你的代码和工业控制器的特性,给你几个具体的排查方向:

1. 先修复地址解析的逻辑漏洞

你代码里判断Broker地址是IP还是域名的方式太粗糙了:只检查最后一位是不是数字,万一遇到mqtt1.example.com这种域名,会被错误当成IP去调用SysSockInetAddr,这个函数解析域名会返回0地址,直接导致连接失败。

换个更可靠的解析逻辑:先尝试用SysSockInetAddr解析(针对IP地址),失败了再用SysSockGetHostByName做域名解析,代码改成这样:

sockAddr.sin_family := SOCKET_AF_INET;
// 先尝试解析为IP地址
sockAddr.sin_addr := SysSockInetAddr(i_sBrokerAddress);
// 如果解析失败(返回0),再尝试域名解析
IF sockAddr.sin_addr = 0 THEN
    sockAddr.sin_addr := SysSockGetHostByName(i_sBrokerAddress);
    // 这里可以加个判断,如果域名解析也失败,直接抛出地址错误
    IF sockAddr.sin_addr = 0 THEN
        q_sDiagMsg := 'Failed to resolve broker address';
        q_xError := TRUE;
        RETURN;
    END_IF
END_IF
sockAddr.sin_port := SysSockHtons(i_uiPort);

这样不管输入是IP还是域名,都能正确处理,避免误判。

2. 排查PFC200的网络通路与防火墙

工业控制器的网络限制比普通PC多得多,这是最容易忽略的点:

  • 登录PFC200的Web管理界面,检查防火墙规则,确保允许出站到MQTT端口(默认1883,加密用8883)的TCP连接
  • 确认控制器所在的工业网络没有ACL限制:比如交换机是否禁止了控制器访问外部Broker的端口,网关是否有出站过滤
  • 如果能访问控制器的命令行,直接用工具测试连通性:
    # 测试Broker是否可达
    ping <你的Broker IP/域名>
    # 测试端口是否开放
    telnet <你的Broker IP/域名> 1883
    

如果telnet连不上,那肯定是网络层面的问题,不用再纠结代码了。

3. 拿到SysSockConnect的具体错误码

你现在只判断了xResult的真假,但SysSockConnect失败时会有具体的错误码,用SysSockGetLastError()就能拿到,把它加到诊断信息里,能直接定位问题:

xResult := SysSockConnect(diSocket, ADR(sockAddr), SIZEOF(sockAddr));
q_sDiagMsg:='Connect to TCP-Server';
IF (xResult) THEN
    q_udiState:=15;
ELSE
    // 新增错误码输出
    q_sDiagMsg := 'Connect failed, error code: ' + INT_TO_STRING(SysSockGetLastError());
END_IF

常见错误码对应的问题:

  • WSAETIMEDOUT:网络不通,确实超时
  • WSAECONNREFUSED:Broker没运行,或者端口没开放
  • WSAEHOSTUNREACH:主机不可达,地址解析错了或者路由有问题
  • WSAEINVAL:Socket状态不对,或者地址结构有误

4. 检查Socket超时的配置逻辑

你设置了wTimeOutValue:=1000,但要确认这个值有没有正确关联到TON_TimeOut的PT参数,而且SysSockConnect本身是阻塞调用,建议在调用前启动TON,同时给Socket设置内置超时(避免系统默认超时和你的TON不同步):

// 在创建Socket后,设置发送/接收超时
VAR
    stTimeout : TIMEVAL;
END_VAR
stTimeout.tv_sec := 10; // 10秒超时,根据需要调整
stTimeout.tv_usec := 0;
SysSockSetsockopt(diSocket, SOL_SOCKET, SO_SNDTIMEO, ADR(stTimeout), SIZEOF(stTimeout));
SysSockSetsockopt(diSocket, SOL_SOCKET, SO_RCVTIMEO, ADR(stTimeout), SIZEOF(stTimeout));

// 启动超时定时器
TON_TimeOut(IN := TRUE, PT := wTimeOutValue);

// 调用连接
xResult := SysSockConnect(diSocket, ADR(sockAddr), SIZEOF(sockAddr));
// 停止定时器
TON_TimeOut(IN := FALSE);

这样能确保超时逻辑的一致性,不会出现Socket还在等,你的TON已经触发的情况。

5. 确认库与固件的兼容性

最后检查一下版本匹配:

  • 你用的Stefan Rossmann的MQTT_Client库是不是最新版本?旧版本可能和新的e!cockpit或者PFC200固件不兼容
  • 确认PFC200的固件是官方最新稳定版,有时候固件的Socket API会有更新,旧库可能适配不好

先从这几个方向排查,应该能找到问题所在。

内容的提问来源于stack exchange,提问作者sashilio

火山引擎 最新活动