Hello everyone, I am a beginner working with PLCs and using a B&R PLC. I am currently experimenting with a printer and its TCP socket communication. The connection works smoothly as long as there are no errors. I have followed the example of using tcpOpen, tcpClient, sending data, and then closing the connection. However, I have encountered an issue where if the connection is lost (due to, for example, a disconnected cable), the tcpClient connection remains stuck in an ERR_FUB_BUSY state indefinitely. Even after reconnecting the cable, it becomes impossible to establish a new connection. The only resolution seems to be restarting the PLC. I have also tested with an external socket tester, and it works perfectly. Can anyone suggest what might be causing this problem? Is it related to not properly closing the socket when the connection is lost? Thank you in advance for any insights. Code: CASE ClientTCP.Step OF 0: (* Opening Ethernet Interface *) IF test_tcp OR start_send_label OR start_send_label_ricetta THEN TcpOpen_0.enable := 1; TcpOpen_0.pIfAddr := 0; (* Select Interface to open *) TcpOpen_0.port := 8000; (* Port on client side to utilize *) TcpOpen_0.options := tcpOPT_REUSEADDR; TcpOpen_0; IF TcpOpen_0.status = 0 THEN TON_timeout_comunicaz_tcpip.IN := TRUE; ClientTCP.Step := 10; ELSIF TcpOpen_0.status = ERR_FUB_BUSY THEN (* Busy *) ELSE ClientTCP.Step := 100; END_IF END_IF 10: (* Connecting to the other Station *) TcpClient_0.enable := 1; TcpClient_0.ident := TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *) TcpClient_0.portserv := 8000; (* Port on server side to use *) TcpClient_0.pServer := ADR('172.17.40.20'); (* Server Address *) TcpClient_0; IF TcpClient_0.status = 0 THEN TON_timeout_comunicaz_tcpip.IN := FALSE; ClientTCP.Step := 20; ELSIF TcpClient_0.status = ERR_FUB_BUSY THEN (* Busy *) IF TON_timeout_comunicaz_tcpip.Q THEN TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); ClientTCP.Step := 40; END_IF ELSIF TcpClient_0.status = tcpERR_INVALID THEN TON_timeout_comunicaz_tcpip.IN := FALSE; ClientTCP.Step := 40; ELSE ClientTCP.Step := 100; END_IF 20: (* Sending Data to the Server *) TcpSend_0.enable := 1; TcpSend_0.ident := TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *) TcpSend_0.pData := ADR(test_string); (* Data to send *) TcpSend_0.datalen := SIZEOF(test_string); (* Data length to send *) TcpSend_0.flags := 0; TcpSend_0; IF TcpSend_0.status = 0 THEN ClientTCP.Step := 40; ELSIF TcpSend_0.status = ERR_FUB_BUSY THEN IF TON_timeout_comunicaz_tcpip.Q THEN TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); ClientTCP.Step := 40; END_IF ELSIF (TcpSend_0.status = tcpERR_SENTLEN) OR (TcpSend_0.status = tcpERR_NOT_CONNECTED) THEN TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); ClientTCP.Step := 40; ELSE TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); label_chunk_ready := FALSE; ClientTCP.Step := 100; END_IF 40: (* Closing Connection *) TcpClose_0.enable := 1; TcpClose_0.ident := TcpOpen_0.ident; TcpClose_0.how := tcpSHUT_RD; TcpClose_0; test_tcp := FALSE; IF TcpClose_0.status = 0 THEN ClientTCP.Step := 0; ELSIF TcpClose_0.status = ERR_FUB_BUSY THEN IF MpAlarmXCheckReaction(gAlarmXCore_Hmi, 'PrinterNetworkError_') THEN ClientTCP.Step := 100; END_IF ELSE ClientTCP.Step := 100; END_IF 100: (* Error Handling Implementation *) TON_timeout_comunicaz_tcpip.IN := FALSE; ClientTCP.Step := 0; END_CASE
Looking for clues?
Is it possible to set a timeout in the programming of a B&R plc to close inactive connections, also known as zombie connections?
A timeout is already in place to automatically close the socket if any errors occur. This feature ensures seamless handling of unexpected issues.
valer85 asked a question: Hello everyone, I am new to PLCs and currently working with a B&R plc. I am experimenting with a printer and its TCP socket communication. The connection works well as long as there are no errors. I have followed the example of using tcpOpen, tcpClient, sending data, and closing the connection. However, if the connection is lost for any reason (such as a disconnected cable), the tcpClient connection remains stuck in the ERR_FUB_BUSY state indefinitely. Even after reconnecting the cable, it is impossible to establish a new connection without restarting the PLC. I have also tested with an external socket tester, and it works perfectly. What am I missing? Is the issue related to not being able to properly close the socket when the connection is lost? Your insights are appreciated. Error Handling code: CASE ClientTCP.Step OF 0: (* Open Ethernet Interface *) IF test_tcp OR start_send_label OR start_send_label_ricetta THEN TcpOpen_0.enable := 1; TcpOpen_0.pIfAddr := 0; (* Which Interface to open *) TcpOpen_0.port := 8000; (* Port on client side to use *) TcpOpen_0.options := tcpOPT_REUSEADDR; TcpOpen_0; IF TcpOpen_0.status = 0 THEN (* TcpOpen successful *) TON_timeout_comunicaz_tcpip.IN := TRUE; ClientTCP.Step := 10; ELSIF TcpOpen_0.status = ERR_FUB_BUSY THEN (* TcpOpen not finished -> redo *) (* Busy *) ELSE (* Go to Error Step *) ClientTCP.Step := 100; END_IF END_IF 10: (* Connect to the other Station *) TcpClient_0.enable := 1; TcpClient_0.ident := TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *) TcpClient_0.portserv := 8000; (* Port on server side to use *) TcpClient_0.pServer := ADR('172.17.40.20'); (* Server Address *) TcpClient_0; IF TcpClient_0.status = 0 THEN TON_timeout_comunicaz_tcpip.IN := FALSE; ClientTCP.Step := 20; ELSIF TcpClient_0.status = ERR_FUB_BUSY THEN (* TcpClient not finished -> redo *) (* Busy *) // timeout for connection IF TON_timeout_comunicaz_tcpip.Q THEN TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); ClientTCP.Step := 40; END_IF ELSIF TcpClient_0.status = tcpERR_INVALID THEN (* Port error -> Close actual connection, and reopen a new one *) TON_timeout_comunicaz_tcpip.IN := FALSE; ClientTCP.Step := 40; ELSE (* Go to Error Step *) ClientTCP.Step := 100; END_IF 20: (* Send Data to the Server *) TcpSend_0.enable := 1; TcpSend_0.ident := TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *) TcpSend_0.pData := ADR(test_string); (* Which data to send *) TcpSend_0.datalen := SIZEOF(test_string); (* Length of data to send *) TcpSend_0.flags := 0; TcpSend_0; IF TcpSend_0.status = 0 THEN (* Data was sent successfully -> close socket *) ClientTCP.Step := 40; ELSIF TcpSend_0.status = ERR_FUB_BUSY THEN (* TcpSend not finished -> redo *) (* Busy *) // timeout IF TON_timeout_comunicaz_tcpip.Q THEN TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); ClientTCP.Step := 40; END_IF ELSIF (TcpSend_0.status = tcpERR_SENTLEN) OR (TcpSend_0.status = tcpERR_NOT_CONNECTED) THEN (* Connection Lost *) TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); ClientTCP.Step := 40; ELSE (* Go to Error Step *) TON_timeout_comunicaz_tcpip.IN := FALSE; MpAlarmXSet(gAlarmXCore_Hmi, 'PrinterNetworkError'); label_chunk_ready := FALSE; ClientTCP.Step := 100; END_IF // --------------------- 40: (* Close connection *) TcpClose_0.enable := 1; TcpClose_0.ident := TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *) TcpClose_0.how := tcpSHUT_RD; //0; TcpClose_0; (* Call the Function *) test_tcp := FALSE; IF TcpClose_0.status = 0 THEN (* Close successful *) ClientTCP.Step := 0; ELSIF TcpClose_0.status = ERR_FUB_BUSY THEN (* TcpClose not finished -> redo *) (* Busy *) IF MpAlarmXCheckReaction (gAlarmXCore_Hmi, 'PrinterNetworkError_') THEN ClientTCP.Step := 100; END_IF ELSE (* Go to Error Step *) ClientTCP.Step := 100; END_IF 100: (* Error Handling implementation is needed *) TON_timeout_comunicaz_tcpip.IN := FALSE; ClientTCP.Step := 0; END_CASE
This code snippet is sourced from the B&R library and automatically comes included when the library is imported into Automation Studio. Feel free to let me know if you would like me to send it to you.
It seems like your code is lacking an error management section for situations where the connection is suddenly lost. You might want to consider incorporating an error checking routine that continuously verifies the connection status. If the connection is lost, this routine should be able to detect it and properly close the sockets or reset the necessary variables. This can save you from having to manually restart the PLC each time. One more thing to verify would be your handling of ERR_FUB_BUSY status. You might not be leaving enough time for tcpClose to complete before calling tcpOpen again, which can leave the FUB in a busy state. Adding some delay or timeout might help.
Hi there! It seems like you might need to implement a kind of error handling mechanism in your code. When the cable is disconnected, this might be causing an error that's not currently being caught or handled, which could be why your TCP client remains in an ERR_FUB_BUSY state. You could try implementing a watchdog timer, which will terminate the connection if there isn't any data transferred in a certain period of time, this could force the closure and free up the port. Also a section of the code which pings the server periodically to check that it's still connected and, if it's not, the connection would be properly terminated and reopened once connection is restored. Hope this helps!
Hi there! It appears like you're properly closing the connection when you're finished sending data but what might be causing issues is how you're handling a lost connection. As soon as the connection gets interrupted mid-communication, your system goes into ERR_FUB_BUSY state and seems to be stuck there. This could be due to the fact that the TcpClose_0 function isn't being called to properly close and reset the connection in those situations. You should consider implementing a case where, upon detecting a lost connection or an ERR_FUB_BUSY state, you properly close the stream via TcpClose_0 and then attempt to re-establish the connection. Also, don't forget to set a reasonable timeout in accordance with your network conditions, like you're doing with TON_timeout_comunicaz_tcpip for normal data sending, to avoid infinite attempts at reconnection.
It sounds like you're on the right track suspecting an issue with the socket not closing properly. When the cable gets disconnected abruptly, it may not get a chance to run your "Closing Connection" code (Step 40), resulting in the ERR_FUB_BUSY state. I'd suggest implementing a periodic check for the connection's viability during the data send process. If the connection isn't alive, trigger Step 40 to close the connection properly and reset. Additionally, also consider setting up a 'watchdog' system that auto-resets the PLC after a certain duration of being stuck in the ERR_FUB_BUSY state. This might help prevent system lock-ups. Lastly, verify that the B&R PLC's firmware and the Ethernet module involved are up to date since this type of issue can sometimes stem from firmware bugs.
It sounds like you're encountering a common issue with TCP connections in PLC programming, especially when dealing with unexpected disconnections. One approach you might consider is implementing a watchdog timer that checks the connection state more frequently and triggers a forced closure of the socket if it detects that the connection is lost. Additionally, after a reconnect, ensure you reset any previous statuses or flags associated with the `TcpClient` and `TcpOpen` before trying to establish a new connection. This can help clear the ERR_FUB_BUSY state and prevent the need to restart the PLC. Make sure to also double-check your error handling logic to ensure it's robust enough to handle various connection scenarios!
It sounds like you're running into a classic issue with socket connections and error handling. One thing to consider is implementing a more robust error recovery routine. When you detect that the connection is lost (e.g., in the `tcpClient_0.status` checking), you could attempt to reset or reinitialize the socket or the entire function after a timeout, rather than staying stuck in an `ERR_FUB_BUSY` state. It might also help to occasionally check the status of the connection to see if it's recoverable before deciding to restart the PLC. Adding some sort of retry mechanism could improve the resilience of your application against transient network issues.
✅ Work Order Management
✅ Asset Tracking
✅ Preventive Maintenance
✅ Inspection Report
We have received your information. We will share Schedule Demo details on your Mail Id.
Answer: Answer: The issue may be related to not properly closing the socket when the connection is lost. This can lead to the tcpClient connection getting stuck in the ERR_FUB_BUSY state.
Answer: Answer: Currently, restarting the PLC seems to be the only resolution for establishing a new connection after encountering this issue.
Answer: Answer: It is important to ensure that the socket is properly closed when the connection is lost. Proper closing of the socket can prevent the tcpClient connection from getting stuck in the ERR_FUB_BUSY state.
Answer: Answer: Best practices for handling TCP socket connections include properly closing the socket when the connection is lost, implementing error handling mechanisms, and ensuring robust communication protocols to handle connection failures effectively.
Join hundreds of satisfied customers who have transformed their maintenance processes.
Sign up today and start optimizing your workflow.