TwinCat3 TCP/IP随机断开报错32770(Socket handle无效)问题咨询
问题根因及修复方案
错误表现对应核心原因
错误码32770明确表示调用fbSocketReceive时传入的Socket句柄已被释放失效,你的代码存在3处逻辑错误直接触发该问题:
- 接收超时被误判为致命错误,触发异常断连逻辑
- 单连接报错后直接关闭监听Socket,导致已建立的连接被底层自动回收
- 接收功能块的触发逻辑不合理,频繁打断正在执行的接收操作,引发底层Socket状态异常
具体修复方案
1. 修正状态3的接收逻辑
将超时错误和真实异常拆分,忽略无数据的超时场景,仅处理真实连接错误:
3: // client connected, send and receive data // 先重置上一次的错误残留 bError := FALSE; nErrorID := 0; fbSocketReceive( sSrvNetId:='', hSocket:=hSocket, cbLen:=SIZEOF(stDataRx), pDest:=ADR(stDataRx), // 不要频繁翻转Execute,保持电平触发,接收完成后自动进入下一次等待 bExecute:= TRUE, // 缩短超时时间,避免长时间阻塞状态机 tTimeout:=T#500MS, bBusy=> , bError=>bError, nErrId=>nErrorID, nRecBytes=> ); IF NOT fbSocketReceive.bBusy THEN // 正常收到数据 IF fbSocketReceive.nRecBytes > 0 THEN fbSocketSend(bExecute:=FALSE); nCntRx:=nCntRx+1; bNewDataReceived:=TRUE; // 远端主动关闭连接,返回0字节,此时才走断连逻辑 ELSIF fbSocketReceive.nRecBytes = 0 THEN iState:=99; // 超时错误直接忽略,下一个周期继续接收即可 ELSIF bError AND nErrorID = 32769 THEN bError := FALSE; nErrorID := 0; // 仅非超时的真实错误才走断连逻辑 ELSIF bError THEN iState:=99; END IF END_IF IF NOT bEnable THEN iState:=99; END_IF
2. 修正错误处理逻辑,不要随意关闭监听Socket
单连接报错不需要关闭监听Socket,避免影响后续新连接接入,也不会导致现有连接被底层回收:
99: // 错误处理,仅关闭当前出错的连接Socket,保留监听Socket fbSocketClose( sSrvNetId:='', hSocket:=hSocket, bExecute:=TRUE, tTimeout:=T#4S, bBusy=> , bError=>bError, nErrId=>nErrorID); IF NOT fbSocketClose.bBusy OR fbSocketClose.bError THEN hSocket.handle:=0; bConnected:=FALSE; // 直接回到等待客户端连接的状态,无需重建监听 iState:=2; END_IF
如果需要支持主动停止服务,可以额外加单独的状态处理监听Socket的关闭逻辑。
3. 修正fbSocketAccept的触发逻辑
移除bExecute:= bAcceptExecute:= NOT bAcceptExecute的翻转逻辑,在状态2时保持bExecute:=TRUE即可,直到有客户端接入或者报错。
额外验证项
- 检查PLC TCP栈配置,确认是否开启了空闲连接自动回收,将空闲超时调整到300秒以上
- 用Wireshark抓包确认断连时FIN包的发送方,如果是Hercules客户端主动发送,检查客户端的保活配置
内容的提问来源于stack exchange,提问作者sharkyenergy
相关产品推荐
相关产品推荐

