Hi to everyone! My application runs smoothly but -again- has to deal with orphaned sockets on the native PLC IDE Modbus TCP Server. Proven that TCP Server handles correcty fairly disconnecting sockets, but not when sudden desconnection occurs, so it requeires a unacceptable manual restart. I've solved this before on sketches, but on IDE, resources seem not so accesible.
I suspect sharing through 'PLCOut.varname' variables is the correct way, but I can't see how to access the resource to handle connections.
I have never worked with PLC IDE Modbus TCP Server so I could be completely wrong. I have two ideas that may work, though.
If there is a way to set timeout on the server socket somehow this may solve your problem.
Alternatively you can periodically scan all the sockets, check if they are opened and close them if needed (or set timeout on them). Valid socket numbers start with LWIP_SOCKET_OFFSET, then there are MEMP_NUM_NETCONN of them. You can check them all in a loop.
Hi @bojan_jurca, many thxs! both approaches looks good. The second one is the usual solution with the Ethernet server class on Arduino sektches. Tested and validated.
Unfortunately, PLC IDE Runtime does not offer so rich interaction as the arduino classes, and documentation is partial in many cases.
My goal i to read the number of connected sockets and reset the PLC when reaching the limit. Shared variables are driving me crazy.
PLC are intended to offer bullet-proof solutions. We do need robust communications, and therefore orphaned sockets should be manageable o at least time-out-killed to avoid the isolation of our adorable Opta.
Thanks again to the community! 1.0.8.0 is a great step in stability. I'll keep $uporting!
You don't need any classes. What I had in mind was something like this:
#include <WiFi.h>
#include <lwip/sockets.h>
void setup() {
}
void loop() {
delay (10000);
for (int sockfd = LWIP_SOCKET_OFFSET; sockfd < LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN; sockfd ++) {
// get socket type
int type;
socklen_t length = sizeof (type);
if (getsockopt (sockfd, SOL_SOCKET, SO_TYPE, &type, &length) == -1)
continue;
if (type != SOCK_STREAM)
continue; // skip SOCK_DGRAM socket
// get server's IP address
char thisIP [INET6_ADDRSTRLEN] = "";
int thisPort = 0;
char remoteIP [INET6_ADDRSTRLEN] = "";
int remotePort = 0;
struct sockaddr_storage addr = {};
socklen_t len = sizeof (addr);
if (getsockname (sockfd, (struct sockaddr *) &addr, &len) != -1) {
struct sockaddr_in6* s = (struct sockaddr_in6 *) &addr;
inet_ntop (AF_INET6, &s->sin6_addr, thisIP, sizeof (thisIP));
// this works fine when the connection is IPv6, but when it is a
// IPv4 connection we are getting IPv6 representation of IPv4 address like "::FFFF:10.18.1.140"
if (strstr (thisIP, ".")) {
char *p = thisIP;
for (char *q = p; *q; q++)
if (*q == ':')
p = q;
if (p != thisIP)
strcpy (thisIP, p + 1);
}
thisPort = ntohs (s->sin6_port);
// DEBUG: Serial.printf ("%i server's IP address: %s port %i\n", sockfd, thisIP, ntohs (s->sin6_port));
// get client's IP address
addr = {};
// len = sizeof (addr);
if (getpeername (sockfd, (struct sockaddr *) &addr, &len) != -1) {
struct sockaddr_in6* s = (struct sockaddr_in6 *) &addr;
inet_ntop (AF_INET6, &s->sin6_addr, remoteIP, sizeof (remoteIP));
// this works fine when the connection is IPv6, but when it is a
// IPv4 connection we are getting something like "::FFFF:10.18.1.140"
if (strstr (remoteIP, ".")) {
char *p = remoteIP;
for (char *q = p; *q; q++)
if (*q == ':')
p = q;
if (p != remoteIP)
strcpy (remoteIP, p + 1);
}
remotePort = ntohs (s->sin6_port);
// DEBUG: Serial.printf ("%i client's IP address: %s port %i\n", sockfd, remoteIP, ntohs (s->sin6_port));
}
if (*thisIP && *remoteIP) {
// the socket has both IP addresses so this is a SOCK_STREAM opened connection socket
// you can check if it belongs to Modbus TCP Server
// count it
// or do something else (close it, ...)
}
} // getsockname
}
}