WiFI client not being "released"

This sketch does what I want except it doesn't "release" the connection. If I disconnect the client the arduino doesn't seem to "get" that. Even downloading the sketch again does not help. The only way I can re-connect to the client is to power down the arduino and start over... then it works .

// create by Nur Ahmad
//github.com/wiwidnadw
//Youtube channel : Digitalneering
//video tutorial for this project : https://youtu.be/jn_oRLLJz64

//Support my platform on github and Youtube by Like, share and subs ! Enjoy

#include <WiFi.h>
#include <arduino_secrets.h>

IPAddress ip(192, 168, 1, 153);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);

#define potentio 17
#define led1 3
#define led2 4
#define led3 5

const char* ssid     = SECRET_SSID;
const char* password = SECRET_PASS;

WiFiServer server(80);

void setup()
{
    WiFiClient client;
    client.setTimeout(2);
    Serial.begin(9600);
    pinMode(led1, OUTPUT);
    pinMode(led2, OUTPUT);
    pinMode(led3, OUTPUT);
    pinMode(potentio, INPUT);    
    delay(10);
    // We start by connecting to a WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

   // WiFi.config(ip,dns,gateway,subnet);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();
}
int value = 0;

void loop(){
  WiFiClient client = server.available();
   if (client) {
   Serial.println("New Client.");
   while (client.connected()){
    char c = client.peek();
  if (c != -1){
    String request = client.readStringUntil('\r');
    //String request = client.readString();
    Serial.println(request);
    Serial.print(request);
    
  if(request.indexOf("led1") != -1 ) {
    digitalWrite(led1, !digitalRead(led1));
  }
  if(request.indexOf("led2") != -1 ) {
    digitalWrite(led2, !digitalRead(led2));
  }
  if(request.indexOf("led3") != -1 ) {
    digitalWrite(led3, !digitalRead(led3));
  }
  }int sensorvalue = analogRead(potentio);
   //Serial.println(sensorvalue);
   client.print(sensorvalue);
   client.print(",");
   client.print("Led 1 = ");
   client.print(digitalRead(led1));
   client.print(",");
   client.print("Led 2 = ");
   client.println(digitalRead(led2));
   
  }  
   client.println("HTTP/1.1 200 OK");
   client.println("Content-type:text/html");
   client.println("");
   //client.println("<meta http-equiv=\"refresh\" content=\"5\" >");
   client.print(",");
 
   delay(1);
   client.stop();
   Serial.println("Client disconnected");
  
  }
}

 
  
            

The only thing I can offer as a clue is that I inserted an "If" to read the buffer if the peek saw something there to read. Before I did that, I could disconnect and reconnect the client. I have tried to retrace what I did that screwed it up but I can't figure it out.
thank you for your assistance

Hi @realolman ,

this might not be the reason but your sketch seems to be sending data to the client

  • repeatedly in a loop even if it does not request anything and
  • after disconnection

See the comments in the loop() part here:

void loop() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New Client.");

    // ********** While Start ***********************************

    while (client.connected()) {   
      char c = client.peek();
      if (c != -1) {
        String request = client.readStringUntil('\r');
        //String request = client.readString();
        Serial.println(request);
        Serial.print(request);

        if (request.indexOf("led1") != -1 ) {
          digitalWrite(led1, !digitalRead(led1));
        }
        if (request.indexOf("led2") != -1 ) {
          digitalWrite(led2, !digitalRead(led2));
        }
        if (request.indexOf("led3") != -1 ) {
          digitalWrite(led3, !digitalRead(led3));
        }
      }
      int sensorvalue = analogRead(potentio);
      //Serial.println(sensorvalue);
      client.print(sensorvalue);
      client.print(",");
      client.print("Led 1 = ");
      client.print(digitalRead(led1));
      client.print(",");
      client.print("Led 2 = ");
      client.println(digitalRead(led2));
    }                              
    
    // ********** While End *************************
    

    // ********* This is sent after client has been disconnected ***
    client.println("HTTP/1.1 200 OK");
    client.println("Content-type:text/html");
    client.println("");
    //client.println("<meta http-equiv=\"refresh\" content=\"5\" >");
    client.print(",");
    delay(1);
    client.stop();
    Serial.println("Client disconnected");

  }
}

Is this your intention?

Instead of

      char c = client.peek();
      if (c != -1) { ... }

you could use

while (client.available()) { ... }

to read only data when they are available and then send only data on a request ?!?

Just a guess ...

Good luck!
ec2021

P.S.: It's the part after //Serial.println(sensorvalue); that is repeated while the client is connected.

Thanks for your reply Yes that is the intent. I am just trying to learn how to use the WiFi part of the Uno rev 4.

It is supposed to send the status of 2 digital outputs and one analog input and also receive from the client to turn on or off those outputs
I had a heck of a time getting it this far. I copied the code and originally it took about 10 seconds to readStringUntil(‘/r’ ); Trying to set the timeout had no effect. ReadString took the same amount of time.

Peeking first and then reading while sending a vbCr (from the client) when there was actually something to read sped things up significantly … without the peek it waited about 10 seconds every iteration of the loop

It seems to me that when i put in the “if” to check whether the “peek” saw anything to read is when i stopped being able to disconnect and reconnect
But i can’t figure out what happened.
I have to cycle power to be able to reconnect
The part at the end (after “this happens after client has disconnected”) never seems to happen now. It used to happen
I am lame at C
Thank you for your reply

This client is local to the setup function (and never used). It is unrelated to the one used in the loop; setting the timeout here has no effect. You could try setting it on the loop one, but it will likely mask your actual problem.

If you're manually sending vbCr, sounds like you're not doing a genuine HTTP request, since that is a requirement. It's what the code you have copied is intended for. In theory, you could make up and use your own simple protocol to do whatever you want. In practice, it should not be done on port 80, which is for HTTP. Can you post your VB code?

Is it really your intention to transmit at "full speed" as many times as possible?

I would rather try to send once and then only again if the data have changed...

If you would use

if (client.available()) {
  // read data here 
}

it should not block ...

So there would be

  • while connected (and inside this)
    • if first time or data changed send data
    • if available (do read, send reply and stop client)

Think that should work ...

Good luck
ec2021

Thank you for your replies
At this point, I am just trying to learn how to send and receive on Wifi I appreciate your advice and will attempt to make use of it. i DID see somewhere that 80 should not be used, and I didn't realize that the timeout would not be used in the loop
here is the vb code... although I would like the arduino code to not be dependent on whether or not there is a request sent from the VB . As I said I am just learning this... what I would like this to do eventually is time stamp changes in the status of the inputs and save them in some manner that I could retrieve to the VB program to use in variables `

'// create by Nur Ahmad'
'//github.com/wiwidnadw
'//Youtube channel : Digitalneering
'//video tutorial for this project : https://youtu.be/jn_oRLLJz64

'//Support my platform on github and Youtube by Like, share and subs ! Enjoy

Imports System.IO
Imports System.Net.Sockets

Public Class Form1
    Dim client As TcpClient
    Dim Rx As StreamReader
    Dim Tx As StreamWriter
    Dim rawdata As String
    Dim dataseparate As Array










    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ToolStripStatusLabel1.Text = "Form Ready"
        CheckForIllegalCrossThreadCalls = False


    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        'connect'
        Try
            client = New TcpClient(IP_address.Text, "80")

            If client.GetStream.CanRead = True Or client.GetStream.CanWrite Then
                Rx = New StreamReader(client.GetStream)
                Tx = New StreamWriter(client.GetStream)
                Threading.ThreadPool.QueueUserWorkItem(AddressOf Connected)

                Button3.Visible = False
                Button4.Visible = True
                Button4.Enabled = True

            End If
            ' Timer1.Enabled = True

        Catch ex As Exception
            MsgBox("Failed to connect")
            'Button3.Visible = True
        End Try

    End Sub

    Function Connected()
        If Rx.BaseStream.CanRead = True Then
            Try
                While Rx.BaseStream.CanRead = True
                    rawdata = Rx.ReadLine
                    dataseparate = rawdata.Split(","",")
                    Label2.Text = dataseparate(0)
                    Label5.Text = dataseparate(1)
                    Label7.Text = dataseparate(2)

                    'Threading.ThreadPool.QueueUserWorkItem(AddressOf MSG1, "Hello World.")

                    ToolStripStatusLabel1.Text = rawdata


                End While
            Catch ex As Exception
                client.Close()
            End Try
            Rx.DiscardBufferedData()
        End If

        Return True

    End Function
    Function MSG1(ByVal Data As String)
        REM Creates a messageBox for new threads to stop freezing
        ToolStripStatusLabel1.Text = Data
        Return True
    End Function
    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        'disconnect'
        'Timer1.Enabled = False
        client.Close()
        Button3.Visible = True
        Button4.Visible = False

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'led 1'

        SendToServer("led1" & vbCr)


    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        'led 2'

        SendToServer("led2" & vbCr)


    End Sub
    Function SendToServer(ByVal data As String)
        Try
            tbxSent.Text = data
            Tx.WriteLine(data)

            Tx.Flush()
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
        tbxSent2.Text = data
        Return True
    End Function

    Private Sub IP_address_TextChanged(sender As Object, e As EventArgs) Handles IP_address.TextChanged

    End Sub

    Private Sub Label7_Click(sender As Object, e As EventArgs) Handles Label7.Click

    End Sub

    Private Sub Label2_Click(sender As Object, e As EventArgs) Handles Label2.Click

    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs)

    End Sub

    Private Sub btnSendReteun_Click(sender As Object, e As EventArgs) Handles btnSendReteun.Click
        SendToServer(vbCr)
    End Sub
End Class

For now , I would just like to be able to disconnect and re-connect to the client without having to go through a power cycle of the arduino
Thank you both

You may give this a try:

/*
  Forum: https://forum.arduino.cc/t/wifi-client-not-being-released/1338339
  Wokwi: https://wokwi.com/projects/419065932299031553

 void changeLedState(byte No)  
    should be changed to
 void changeLedState(int No) !!!!!

 Not changed here for traceability reasons ...

*/

#include <WiFi.h>
#include <arduino_secrets.h>

IPAddress ip(192, 168, 1, 153);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);

const byte potentio {17};

struct ledType {
  byte pin;
  byte state;
};

ledType leds[] = {
  {3, LOW},
  {4, LOW},
  {5, LOW}
};

int noOfLeds = sizeof(leds) / sizeof(leds[0]);
boolean ledStateChanged = true;

int oldSensorValue = -1;

const char* ssid     = SECRET_SSID;
const char* password = SECRET_PASS;

WiFiServer server(80);

void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < noOfLeds; i++) {
    pinMode(leds[i].pin, OUTPUT);
  }
  //  pinMode(potentio, INPUT); // not required for analogRead()
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  // WiFi.config(ip,dns,gateway,subnet);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.begin();
}



void loop() {
  WiFiClient client = server.available();
  if (client) {
    client.setTimeout(2);
    Serial.println("New Client.");
    oldSensorValue = -1;
    while (client.connected()) {
      sendData(client);
      if (requestHandled(client)) {
        sendData(client);
        delay(1);
        client.stop();
      }
    }
    Serial.println("Client disconnected");
  }
}

boolean requestHandled(WiFiClient &aClient) {
  if (aClient.available()) {
    String request = aClient.readStringUntil('\r');
    Serial.println(request);
    if (request.indexOf("led1") != -1 ) {
      changeLedState(1);
    }
    if (request.indexOf("led2") != -1 ) {
      changeLedState(2);
    }
    if (request.indexOf("led3") != -1 ) {
      changeLedState(3);
    }
    return true;
  }
  return false;
}

void changeLedState(byte No) {
  No--;
  if (No >= 0 && No < noOfLeds) {
    leds[No].state = !leds[No].state;
    digitalWrite(leds[No].pin, leds[No].state);
    ledStateChanged = true;
  }
}

void sendData(WiFiClient &aClient) {
  int sensorValue = analogRead(potentio);
  if (sensorValue != oldSensorValue || ledStateChanged) {
    ledStateChanged = false;
    oldSensorValue = sensorValue;
    aClient.print(sensorValue);
    for (int i = 0; i < noOfLeds; i++ ) {
      char msg[20];
      sprintf(msg, ", Led %d = %d", i + 1, leds[i].state);
      Serial.println(msg);
      aClient.print(msg);
    }
    aClient.println();
    aClient.println("HTTP/1.1 200 OK");
    aClient.println("Content-type:text/html");
    aClient.println("");
    //client.println("<meta http-equiv=\"refresh\" content=\"5\" >");
    aClient.print(",");
  }
}

There is still room for improvement. It compiles (on Wokwi) but I have not tested it ...

It will return the state of all three leds not just led1 and led2, but you can easily adjust this in the lines

  for (int i = 0; i < noOfLeds; i++ ) {
      char msg[20];
      sprintf(msg, ", Led %d = %d", i + 1, leds[i].state);
      Serial.println(msg);
      aClient.print(msg);
    }

If you write i < noOfLeds-1 it will only send the data of led1 and led2 ...

Hope it works for you ...
Good luck!
ec2021

P.S.: Just tested it with an ESP32 and it works there ... I would just recommend to change the line

void changeLedState(byte No) {

to

void changeLedState(int No) {

as I'm doing a "No--;" ... It still works with byte but it's not nice ...

Here is the sketch with this change

Corrected Sketch
/*
  Forum: https://forum.arduino.cc/t/wifi-client-not-being-released/1338339
  Wokwi: ... not changed there ...

*/

#include <WiFi.h>
#include <arduino_secrets.h>

IPAddress ip(192, 168, 1, 153);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);

const byte potentio {17};

struct ledType {
  byte pin;
  byte state;
};

ledType leds[] = {
  {3, LOW},
  {4, LOW},
  {5, LOW}
};

int noOfLeds = sizeof(leds) / sizeof(leds[0]);
boolean ledStateChanged = true;

int oldSensorValue = -1;

const char* ssid     = SECRET_SSID;
const char* password = SECRET_PASS;

WiFiServer server(80);

void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < noOfLeds; i++) {
    pinMode(leds[i].pin, OUTPUT);
  }
  //  pinMode(potentio, INPUT); // not required for analogRead()
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  // WiFi.config(ip,dns,gateway,subnet);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.begin();
}



void loop() {
  WiFiClient client = server.available();
  if (client) {
    client.setTimeout(2);
    Serial.println("New Client.");
    oldSensorValue = -1;
    while (client.connected()) {
      sendData(client);
      if (requestHandled(client)) {
        sendData(client);
        delay(1);
        client.stop();
      }
    }
    Serial.println("Client disconnected");
  }
}

boolean requestHandled(WiFiClient &aClient) {
  if (aClient.available()) {
    String request = aClient.readStringUntil('\r');
    Serial.println(request);
    if (request.indexOf("led1") != -1 ) {
      changeLedState(1);
    }
    if (request.indexOf("led2") != -1 ) {
      changeLedState(2);
    }
    if (request.indexOf("led3") != -1 ) {
      changeLedState(3);
    }
    return true;
  }
  return false;
}

void changeLedState(int No) {
  No--;
  if (No >= 0 && No < noOfLeds) {
    leds[No].state = !leds[No].state;
    digitalWrite(leds[No].pin, leds[No].state);
    ledStateChanged = true;
  }
}

void sendData(WiFiClient &aClient) {
  int sensorValue = analogRead(potentio);
  if (sensorValue != oldSensorValue || ledStateChanged) {
    ledStateChanged = false;
    oldSensorValue = sensorValue;
    aClient.print(sensorValue);
    for (int i = 0; i < noOfLeds; i++ ) {
      char msg[20];
      sprintf(msg, ", Led %d = %d", i + 1, leds[i].state);
      Serial.println(msg);
      aClient.print(msg);
    }
    aClient.println();
    aClient.println("HTTP/1.1 200 OK");
    aClient.println("Content-type:text/html");
    aClient.println("");
    //client.println("<meta http-equiv=\"refresh\" content=\"5\" >");
    aClient.print(",");
  }
}

I am a bit shocked at all the trouble you went to for this... I certainly appreciate it. I feel bad telling you that it doesn't work for me . It compiles and downloads and when I connect, it does this on the serial monitor:
, Led 3 = 0

, Led 1 = 0

, Led 2 = 0

, Led 3 = 0

, Led 1 = 0

, Led 2 = 0

, Led 3 = 0

, Led 1 = 0

, Led 2 = 0

, Led 3 = 0

Client disconnected

I really appreciate what you've done here,but... I can't get it to work

This sketch does pretty much what I want at this point. It connects to my VB form with buttons on the form , sends the value of an analog input that appears to be constant ( I know it is not ), and it reads buttons I have in my VB form to turn on and off 2 LEDS

The only problem is that I can't connect and reconnect without cycling power to the arduino.

// create by Nur Ahmad
//github.com/wiwidnadw
//Youtube channel : Digitalneering
//video tutorial for this project : https://youtu.be/jn_oRLLJz64

//Support my platform on github and Youtube by Like, share and subs ! Enjoy

#include <WiFi.h>
#include <arduino_secrets.h>

IPAddress ip(192, 168, 1, 153);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);

#define potentio 17
#define led1 3
#define led2 4
#define led3 5

const char* ssid     = SECRET_SSID;
const char* password = SECRET_PASS;

WiFiServer server(1000);

void setup()
{
    WiFiClient client;
    client.setTimeout(2);
    Serial.begin(9600);
    pinMode(led1, OUTPUT);
    pinMode(led2, OUTPUT);
    pinMode(led3, OUTPUT);
    pinMode(potentio, INPUT);    
    delay(10);
    // We start by connecting to a WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

   // WiFi.config(ip,dns,gateway,subnet);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();
}
int value = 0;

void loop(){
  WiFiClient client = server.available();
   if (client) {
   Serial.println("New Client.");
   while (client.connected()){
    char c = client.peek();
  if (c != -1){
    String request = client.readStringUntil('\r');
    //String request = client.readString();
    Serial.println(request);
    Serial.print(request);
    
  if(request.indexOf("led1") != -1 ) {
    digitalWrite(led1, !digitalRead(led1));
  }
  if(request.indexOf("led2") != -1 ) {
    digitalWrite(led2, !digitalRead(led2));
  }
  if(request.indexOf("led3") != -1 ) {
    digitalWrite(led3, !digitalRead(led3));
  }
  }int sensorvalue = analogRead(potentio);
   //Serial.println(sensorvalue);
   client.print(sensorvalue);
   client.print(",");
   client.print("Led 1 = ");
   client.print(digitalRead(led1));
   client.print(",");
   client.print("Led 2 = ");
   client.println(digitalRead(led2));
   
  }  
   client.println("HTTP/1.1 200 OK");
   client.println("Content-type:text/html");
   client.println("");
   //client.println("<meta http-equiv=\"refresh\" content=\"5\" >");
   client.print(",");
 
   delay(1);
   client.stop();
   Serial.println("Client disconnected");
  
  }
}

 
  
            

I am unable to determine why that is.
The only clue I have is that it started doing this when I put in an "if" statement to determine if there was anything in the buffer to read

   char c = client.peek();
  if (c != -1){
    String request = client.readStringUntil('\r');
    //String request = client.readString();
    Serial.println(request);
    Serial.print(request);

Before I made this modification I could disconnect and reconnect whenever I wanted without cycling power. Even downloading the same or a modified sketch does not do it... I have to power the arduino off and back up. I have tried going back to before the modification but I am unable to figure out what is wrong

I think my problem is probably something to do with the C language...
I am sure it is not the best way to do it but it is where I am at this point and I understand a lot of it and why it is the way it is.

No worries :wink:

My sketch works on an ESP32 with a standard browser. I assume that it's your VB code that behaves differently but didn't have the time to check.

Now I had some time to "re-engineer" your VB application and check what causes your problems.

The main reason is a typo (that is already in the source on github!):

  Function Connected()
        If Rx.BaseStream.CanRead = True Then
            Try
                While Rx.BaseStream.CanRead = True
                    rawdata = Rx.ReadLine
                 ' ********************************************'
                  ' Typo in the next line, it should read (",")!'
                    dataseparate = rawdata.Split(","",")  
                    Label2.Text = dataseparate(0)
                    Label5.Text = dataseparate(1)
                    Label7.Text = dataseparate(2)

                    'Threading.ThreadPool.QueueUserWorkItem(AddressOf MSG1, "Hello World.")

                    ToolStripStatusLabel1.Text = rawdata


                End While
            Catch ex As Exception
                client.Close()
            End Try
            Rx.DiscardBufferedData()
        End If

        Return True

The typo creates an exception which is caught by "Catch ex As Exception" and immediately leads to "client.close()".

Here is your updated VB code (that also displays when "Disconnected"):

'// create by Nur Ahmad'
'//github.com/wiwidnadw
'//Youtube channel : Digitalneering
'//video tutorial for this project : https://youtu.be/jn_oRLLJz64

'//Support my platform on github and Youtube by Like, share and subs ! Enjoy

REM Modified from Forum !!!!!

Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Reflection.Emit

Public Class Form1
    Dim client As TcpClient
    Dim Rx As StreamReader
    Dim Tx As StreamWriter
    Dim rawdata As String
    Dim dataseparate As Array



    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ToolStripStatusLabel1.Text = "Form Ready"
        CheckForIllegalCrossThreadCalls = False


    End Sub

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        'connect'
        Try
            client = New TcpClient(IP_address.Text, "80")

            If client.GetStream.CanRead = True Or client.GetStream.CanWrite Then
                Rx = New StreamReader(client.GetStream)
                Tx = New StreamWriter(client.GetStream)
                Threading.ThreadPool.QueueUserWorkItem(AddressOf Connected)

                Button3.Visible = False
                Button4.Visible = True
                Button4.Enabled = True

            End If
            ' Timer1.Enabled = True

        Catch ex As Exception
            MsgBox("Failed to connect")
            'Button3.Visible = True
        End Try

    End Sub

    Function Connected()
        If Rx.BaseStream.CanRead = True Then
            Try
                While Rx.BaseStream.CanRead = True
                    rawdata = Rx.ReadLine
                    ToolStripStatusLabel1.Text = rawdata
                    dataseparate = rawdata.Split(",")
                    Label2.Text = dataseparate(0)
                    Label5.Text = dataseparate(1)
                    Label7.Text = dataseparate(2)

                    'Threading.ThreadPool.QueueUserWorkItem(AddressOf MSG1, "Hello World.")
                End While
            Catch ex As Exception
                client.Close()
                ToolStripStatusLabel1.Text = "Disconnected!"
            End Try
            Rx.DiscardBufferedData()
        End If

        Return True

    End Function
    Function MSG1(ByVal Data As String)
        REM Creates a messageBox for new threads to stop freezing
        ToolStripStatusLabel1.Text = Data
        Return True
    End Function
    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        'disconnect'
        'Timer1.Enabled = False
        client.Close()
        Button3.Visible = True
        Button4.Visible = False

    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'led 1'

        SendToServer("led1" & vbCr)


    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        'led 2'

        SendToServer("led2" & vbCr)


    End Sub
    Function SendToServer(ByVal data As String)
        Try
            tbxSent.Text = data
            Tx.WriteLine(data)

            Tx.Flush()
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
        tbxSent2.Text = data
        Return True
    End Function

    Private Sub IP_address_TextChanged(sender As Object, e As EventArgs) Handles IP_address.TextChanged

    End Sub

    Private Sub Label7_Click(sender As Object, e As EventArgs) Handles Label7.Click

    End Sub

    Private Sub Label2_Click(sender As Object, e As EventArgs) Handles Label2.Click

    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs)

    End Sub

    Private Sub btnSendReteun_Click(sender As Object, e As EventArgs) Handles btnSendReteun.Click
        SendToServer(vbCr)
    End Sub
End Class

and here the Arduino code that works with this VB program (here at my PC at least :wink: ):

/*
  Forum: https://forum.arduino.cc/t/wifi-client-not-being-released/1338339
 
  2025/01/04 
  ec2021

*/

#include <WiFi.h>
#include <arduino_secrets.h>

/*
IPAddress ip(192, 168, 1, 153);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(192, 168, 1, 1);
*/

#if defined(ESP32)
const byte potentio {34};
const byte led1Pin  { 5};
const byte led2Pin  {18};
const byte led3Pin  {19};
#else
const byte potentio {17};
const byte led1Pin  { 3};
const byte led2Pin  { 4};
const byte led3Pin  { 5};
#endif


struct ledType {
  byte pin;
  byte state;
};

ledType leds[] = {
  {led1Pin, LOW},
  {led2Pin, LOW},
  {led3Pin, LOW}
};

int noOfLeds = sizeof(leds) / sizeof(leds[0]);
boolean ledStateChanged = true;

int oldSensorValue = -1;

const char* ssid     = SECRET_SSID;
const char* password = SECRET_PASS;

WiFiServer server(80);

void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < noOfLeds; i++) {
    pinMode(leds[i].pin, OUTPUT);
  }
  //pinMode(potentio, INPUT); // not required for analogRead()
  delay(10);
  // We start by connecting to a WiFi network
#if defined(ESP32)
  Serial.println("Compiled for ESP32");
#else
  Serial.println("Compiled for other Board");
#endif
  Serial.print("Connecting to ");
  Serial.println(ssid);

  // WiFi.config(ip,dns,gateway,subnet);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.begin();
}



void loop() {
  WiFiClient client = server.available();
  if (client) {
    client.setTimeout(2);
    Serial.println("New Client.");
    oldSensorValue = -1;
    while (client.connected()) {
      sendData(client);
      handleRequest(client);
    }
     Serial.println("Client disconnected");
  }
}

void handleRequest(WiFiClient &aClient) {
  if (aClient.available()) {
    String request = aClient.readStringUntil('\r');
    Serial.println(request);
    if (request.indexOf("led1") != -1 ) {
      changeLedState(1);
    }
    if (request.indexOf("led2") != -1 ) {
      changeLedState(2);
    }
    if (request.indexOf("led3") != -1 ) {
      changeLedState(3);
    }
  }
}

void changeLedState(int No) {
  No--;
  if (No >= 0 && No < noOfLeds) {
    leds[No].state = !leds[No].state;
    digitalWrite(leds[No].pin, leds[No].state);
    ledStateChanged = true;
  }
}

void sendData(WiFiClient &aClient) {
  int sensorValue = analogRead(potentio);
  if (sensorValue != oldSensorValue || ledStateChanged) {
    ledStateChanged = false;
    oldSensorValue = sensorValue;
    aClient.print(sensorValue);
    for (int i = 0; i < noOfLeds; i++ ) {
      char msg[20];
      sprintf(msg, ", Led %d = %d", i + 1, leds[i].state);
      Serial.println(msg);
      aClient.print(msg);
    }
    aClient.println();
  }
}

The #if defined() lines should make sure that you don't have to change the pins for your application; I had to use different pins for the ESP32 ...

Good luck!
ec2021

P.S.: Be aware that the VB program creates an exception in this function if you close it while it is connected :

Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.'
    <System.Diagnostics.DebuggerNonUserCode()>
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)  ' <- This creates an error!
        End Try
    End Sub

To have a "clean" code the VB program should actively close an open connection when it's terminated.

I can’t believe all the trouble you went to here…. Thank you very much.

I won’t be able to try it for a while but I will certainly let you know.

Thank you

It was no trouble, took just some time to setup the components in Visual Studio and to get it running.

The error message of the VS debugger told that you cannot use a disposed component. So I had to find out why the connection was already closed when the buttons led 1 or led 2 was pushed.

In parallel I saw that the received message was not correctly split into the expected parts.

Both observations directed me to the function where I finally found the typo ...

I removed most parts (not all) which I considered unnecessary in your Arduino code. E.g. the html messages would only be interesting if you use a standard web browser.

There's still room for improvement but it should work now.

ec2021;
I appreciate everything you have done, I truly do... but this doesn't work for me.
If you are still willing to help, please read my post #9.
The whole thing - arduino and VB - does what I want it to do... the only problem I have with it is this: when I disconnect the VB client from the arduino, I can't reconnect... even if I download a new or the same sketch to the arduino ... I have to cycle power on the arduino
I have no problems with anything else... I don't see how I could have connected in the first place if there was a problem with the VB. I did get the exception you mentioned if I shut it down without disconnecting, but I never got any exceptions otherwise

As I said, I do appreciate you very much and I want you to know that , but I don't think we're on the same page.

Can you explain what happens if you try the Arduino sketch and the VB code I have posted?

You should properly indent your code. This is easily done in the IDE by auto-formatting: right-click on a blank area of the editor, and choose Format Document from the menu. It helps make things clearer for everyone, including you.

First, you can get away with this on R4 because plain char happens to be signed. But peek and read actually return an int

  • 0 to 255 if a byte is available; or
  • -1 otherwise

257 different possible return values. By blindly assigning to char, that reduces to 256 values. On Uno, that means you cannot distinguish between 255 -- an unlikely byte, but hardly impossible -- and -1. On ESP32, where plain char is unsigned, the test (c != -1) is always true, because c is promoted to integer for the equality test.

Second, another difference from ESP32: it looks like on R4, a read takes ten seconds to time out. This may be in the underlying modem code. This is why readString and readStringUntil-something-that-wasn't-there were taking that long. If you were to do client.setTimeout(12000), then it would take twenty seconds to time out:

  • first read takes ten seconds to return
  • it hasn't been twelve seconds yet, try again
  • another ten seconds

This applies when reading into a buffer -- read(uint8_t *buf, size_t len) -- as well. R4 waits to fill the buffer, while ESP32 will give up immediately if there is nothing. So you should only read as many bytes as you know are there.

I have seen some implementations of available return -1 ("less than nothing" I suppose) for certain conditions with no data; so while you can usually use

while (client.available())

only 0 evaluates to false, so it is safer to use

while (client.available() > 0)

The actual problem

it appears that if you do not read all the available bytes, the connection stays open; and peek will return -1 even though there were/are bytes remaining. Again, this may be something on the modem side. You need to, for the lack of a better term, drain all the bytes-to-read, even if you ignore them. (Flush is the term to send all the buffered bytes-to-write.)

readStringUntil('\r') will return up to that CR (and discard it). But you are sending with

which in turn does

which sends the data, plus the CoreNewLine, which is either

  • \r and \n (in which case why did you need to add & vbCr?); or
  • just \n

In either case, you have at least the \n left over. This can be seen if you replace the start of the loop with

void loop() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New Client.");
    unsigned long neg1 = 0;
    while (client.connected()) {
      int c = client.peek();
      if (c == -1) {
        if (++neg1 % 250 == 0) {
          Serial.print("neg1: ");
          Serial.println(neg1);
        }
      } else {
        Serial.print("peek: ");
        Serial.println(c, HEX);
        String request = client.readStringUntil('\r');

        Serial.print(request);
        Serial.print("<<--== length: ");
        Serial.println(request.length());

which, when receiving "Hello, world\r\n", will print

New Client.
peek: 48
Hello, world<<--== length: 12
neg1: 250
neg1: 500
neg1: 750

indicating that peek is stuck at -1, and the client stays connected, even after the caller disconnects.

Maybe solution

So you don't need peek if you just check available. And instead of reading one byte at a time, you could grab as many as you would expect in a single packet, which is hundreds of bytes. But your commands are like "led1" -- four bytes. Use the same buffer to drain the stream. Get rid of the irrelevant HTTP stuff. Try

void loop() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New Client.");
    while (client.connected()) {
      int avail = client.available();
      if (avail > 0) {
        uint8_t buf[16];  // Large enough for supported requests
        avail = min(avail, sizeof(buf));
        avail = client.read(buf, avail);  // Expect requests at beginning
        String request(buf, avail);  // Make it a String for convenience
        // Reuse buffer to drain remaining bytes, if any
        while ((avail = client.available()) > 0) {
          avail = min(avail, sizeof(buf));
          Serial.print("drain: ");
          Serial.println(client.read(buf, avail));  // only read what is present
        }

        Serial.print(request);
        Serial.print("<<--== length: ");
        Serial.println(request.length());

        if (request.indexOf("led1") != -1) {
          digitalWrite(led1, !digitalRead(led1));
        }
        if (request.indexOf("led2") != -1) {
          digitalWrite(led2, !digitalRead(led2));
        }
        if (request.indexOf("led3") != -1) {
          digitalWrite(led3, !digitalRead(led3));
        }
      }
      int sensorvalue = analogRead(potentio);
      Serial.println(sensorvalue);
      client.print(sensorvalue);
      client.print(",");
      client.print("Led 1 = ");
      client.print(digitalRead(led1));
      client.print(",");
      client.print("Led 2 = ");
      client.println(digitalRead(led2));
    }
    Serial.println("Client disconnected");
  }
}

You could take a more robust approach and send the length of your request as the first byte(s). By using the UTF-8 encoding scheme, you can tell from the first byte whether the length is one, two, three, or four bytes long -- for lengths past one million; then wait for that many bytes.

Here's the Python test script I used

import socket, datetime

HOST = '192.168.1.104'
PORT = 2025  # ports below 1024 are "Well-Known"

with socket.socket() as s:  # defaults to (family=AF_INET, type=SOCK_STREAM)
    s.connect((HOST, PORT)) # AF_INET tuple
    s.sendall(b"Hello, world")
    counter = 0
    while counter < 200:
        data = s.recv(1024)
        count = len(data.split(b',')) # rough count; accuracy not important
        print(f"{datetime.datetime.now()} received {len(data)} bytes with {count} items: {data!r}")
        counter += count
        if counter % 5 == 0:
            s.sendall(f"got {counter} so {'far' * counter}".encode())
    print(f"stopped after {counter} items")

Finally, you probably don't need to be constantly sending the readings back; do they change that often?

Thank you very much ... there is a lot to digest here and I get the feeling that I will be able to "cure" my sketch with this info. I am just trying to learn how to use the arduino and the wifi... I have no experience with either. I CAN answer the last question , though... The analog input is connected to a pot, and the faster it sends , the "righter" the display looks when I turn the pot... Certainly the 10 second update didn't look good at all.
I have commented out or deleted everything in the sketch except what is necessary to connect, disconnect, and reconnect the VB client. It does do that now, but nothing else.
I will go back through, adding things, taking into consideration what you have posted until I get this thing figured out.
thank you very much
One thing good about having problems... you usually learn and remember something

I don't have it here now but I didn't want to be rude... I know you know your stuff, and I really appreciate what you have done ... you did way more than I expected.
I think it kept serially printing the led1=0 led2=0 about 10 times and then disconnected the client, before I did anything with the VB form
Also, I kinda knew what was going on with the stuff I had and wanted to try to "fix " that stuff... I didn't know what was going on with your stuff much at all... all my shortcomings... not yours.
thank you very much for all you have done.

It's up to you if course how to proceed

I just recommend to definitely change

dataseparate = rawdata.Split(","",")

to

dataseparate = rawdata.Split(",")

as this is a real mistake and will not allow to separate the received string into the expected output (unless the VB code you use is not exactly the one you posted;-) ).

You should also carefully read the post of @kenb4 !

It might be very helpful to know which board you are using. Presumably a R4, isn't it?

Anyway good luck!

Thank you Ec2021

You are a good person.

realolman