arduino-libraries / Ethernet

Ethernet Library for Arduino
http://arduino.cc/
259 stars 264 forks source link

Connected() returns true for connections already closed #147

Closed Miq1 closed 4 years ago

Miq1 commented 4 years ago

I got two W5500 boards connected to the same network, one as a server, the second as a client connecting that server.

As sockets are a sparse resource on the W5500, I am trying to re-use already opened connections normally. So my client code is looking like

// Empty the RX buffer - just in case...
      while (instance->MT_client.available()) instance->MT_client.read();
      // Is the target host/port still the same as last turn?
      if (instance->MT_lastHost != request->targetHost || instance->MT_lastPort != request->targetPort) {
        // It is different. If client is connected, disconnect
        if (instance->MT_client.connected()) {
          // Is connected - cut it
          instance->MT_client.stop();
        }
      }
      // if client is disconnected (we will have to switch hosts)
      if (!instance->MT_client.connected()) {
        // It is disconnected. connect to host/port from queue
        int retc = instance->MT_client.connect(request->targetHost, request->targetPort);
      }
      // Are we connected (again)?
      if (instance->MT_client.connected()) {
        // Yes. Send the request via IP
        instance->send(request);
        // Get the response - if any
        TCPResponse *response = instance->receive(request);

In short:

get target host/port
if same as before AND connected
  use connection
else
  connect to it
  use connection just made
endif

The server is closing the connection with client.stop(), though, if all data has been sent, to save sockets. This is done like

              ec->write(outBuf, outLen);
              delay(50);
              ec->flush();
              ec->stop();
              delay(50);    

(the final delay() seemed to be necessary to not prematurely cut the communication, since the client ec is destroyed immediately after)

So my expectation was connected() would return false on the next attempt and thus force a fresh connect. The time between consecutive requests can go down to a few milliseconds, by the way.

But as I learned, connected() will return true most of the time, despite cleaning the RX buffers etc.

I found a strange workaround (https://forum.arduino.cc/index.php?topic=245829.0 sending a single character before the stop(). This indeed changed the behaviour of connected() as desired, but the sent character sporadically popped up in freshly opened connections, hence destroying my data protocol. So I had to remove it again.

The current result is, that after some time all sockets are eaten up or stuck on the server, so that no connection can be made any more. Very infrequently single sockets seem to be cleaned up after a long time and will allow few requests to be serviced.

This is unpleasant, to say the least...

Note: A Linux box sitting next to the client is able to contact the same server with the identical scheme as often as it likes - each request is served correctly, without hang-ups.

Miq1 commented 4 years ago

Found at least part of it: I had a 20ms waiting time after client.available() got 0 where I looked for potential stray bytes following. This is probably obsolete, since the W5500 will collect the bytes in its RX buffer and make sure the packets are complete. After removing the wait period things got better, there are no hangups any more now.

Sorry to have bothered you... 😊