W5500 : Limiting connections to my TCP server

Hello,

I'm working on a basic RS422 to Ethernet converter using an ATmega2560 and a Wiznet W5500 module. My goal is to create two TCP servers on a single ATmega2560, each listening on a different port. These servers are intended to handle only one client connection at a time and should not allow multiple clients to connect simultaneously.

However, I'm encountering an issue: when one client is connected to a server, another client is able to connect to the same server, but it cannot send or receive any messages. To test this, I'm using the Hercules tool on Windows to establish multiple sessions.

The problem becomes more apparent when the previously connected client disconnects; all the messages that the new client attempted to send are suddenly sent to the serial port.

I've shared the complete project on GitHub: link

I've also included the function responsible for managing TCP connections below for reference. Can anyone offer suggestions on what might be causing this issue?

Any insights or guidance would be greatly appreciated.

Thank you.

void checkTCPdata()
{
  static uint32_t timeSinceLastBroadcast = millis();
  static uint32_t timeSinceLastModeSent = millis();
  uint32_t currentTime = millis();
  char ipAddressStr[16]; // Adjust size as needed
  char rc = 0;
  EthernetClient tempClient;
  if (!g_localDataclient.connected())
  {

    tempClient = g_dataServer_local_cnx->accept(); // accept incoming connections
    if (tempClient)
    {
      g_localDataclient.stop();
      g_localDataclient = tempClient;
    }
  }

  if (g_localDataclient.connected())
  {
    while (g_localDataclient.available() > 0) // if any data is received on TCP, write to serial
    {
      rc = g_localDataclient.read();
      Serial.write(rc);
    }
  }

  if (!g_remoteDataclient.connected())
  {

    tempClient = g_dataServer_remote_cnx->accept(); // accept incoming connections

    if (tempClient)
    {
      g_remoteDataclient.stop();
      g_remoteDataclient = tempClient;
    }
  }
  if (g_remoteDataclient.connected())
  {

    if (!g_localDataclient.connected())
    {
      while (g_remoteDataclient.available() > 0) // if any data is received on TCP, write to serial
      {
        rc = g_remoteDataclient.read();
        Serial.write(rc);
      }
    }
    else
    {
      while (g_remoteDataclient.available() > 0) // if any data is received on TCP, write to serial
      {
        rc = g_remoteDataclient.read();
      }
    }
  }

  if ((currentTime - timeSinceLastBroadcast) >= 20000) // if there has not been any client connection broadcast own IP on port 9999
  {

    if (!g_localDataclient.connected() && !g_remoteDataclient.connected())
    {
      ipAddressToString(g_ip, ipAddressStr, sizeof(ipAddressStr));
      timeSinceLastBroadcast = millis();
      Udp.beginPacket(g_broadcastIP, 9999);
      Udp.write(ipAddressStr);
      Udp.endPacket();
    }
  }

  if ((currentTime - timeSinceLastModeSent) >= 15000) // if there has not been any client connection broadcast own IP on port 9999
  {
    timeSinceLastModeSent = millis();
    if (g_localDataclient.connected() && g_remoteDataclient.connected())
    {
      g_localDataclient.write("L&R\r\n");
      g_remoteDataclient.write("L&R\r\n");
    }
    else if (g_localDataclient.connected() && !g_remoteDataclient.connected())
    {
      g_localDataclient.write("L\r\n");
    }
    else if (!g_localDataclient.connected() && g_remoteDataclient.connected())
    {
      g_remoteDataclient.write("R\r\n");
    }
  }
}

server.available() always returns a first connected client which has data available

you could use server.accept to get every client only once

Thank you for your suggestion.

In my application, it's crucial to establish a connection with the first client, regardless of whether it immediately sends data or not. Additionally, I need to ensure that once this initial connection is made, no other clients should be able to connect simultaneously.

Based on this requirement, it seems that using server.available() may not be suitable for my use case, as it retrieves the first connected client with data available. Instead, I believe server.accept() might be a more appropriate approach, allowing me to manage client connections as per my specifications.

If you have any further insights or suggestions on how to implement this, I'd greatly appreciate your input.

Thank you.

if you have the active client reject other clients by stopping them after retrieving them from accept()

This might be a good workaround, I will try this. But, I still do not understand how and why the second connection is being made..

I'm no specialist, but could limiting the amount of sockets of the W5500 help ? Default is 4, when using large buffers it is reduced to 2, but why not just 1 ?

Thanks for the suggestion.

But, I actually have three different servers running on three different ports. I just want to limit one client per server.

a second client connects and the library internally accepts the connection and adds the client to its list of clients.

if you have the active client reject other clients by stopping them after retrieving them from accept()

I have implemented this and it seems to be working currently as per my requirement of only serving one client per server. My only doubt is whether server.accept() may take too much time on every loop and data coming on the serial port is lost because of that.

a second client connects and the library internally accepts the connection and adds the client to its list of clients.

Is there any scope to modify the library? Can you point me where this might be happening?

every new connection is accepted in the Wiznet firmware at listening ports. you can't change it. you would have to stop listening (but the firmware may close the associated connections). EthernetServer in Ethernet library doesn't have end(). maybe it is possible to add it.

Thank you for the guidance.