Strange behavior of TCPServer and TCPClient

Hey guys,

I’m trying to create a mini HTTP server, but I fail to make it work.
I only get the first request, and then ignores the client.stop(), running in an infinite loop.
I tried putting dalys, but I get strange behavior, hanging the core.
Do not know if I’m doing something wrong, or is there some bug.

Sorry for my English.

TCPServer server = TCPServer(80);

void setup()
{
    server.begin();

    Serial.begin(9600);

    delay(1000);

    Serial.println(Network.localIP());
    Serial.println(Network.subnetMask());
    Serial.println(Network.gatewayIP());
    Serial.println(Network.SSID());
}

void loop()
{
    TCPClient client = server.available();

    if (client == true) 
    {
        Serial.println("Client true");
        if (client.connected()) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println();
            client.print("Hello world ");
            client.println("<br />");
        }
        Serial.println("Hello world ...");


        if (client.connected()) {
            Serial.println("Client conected");
            client.flush();
            client.stop();
            Serial.println("Client Stop");
        }
        else
        {
            Serial.println("Client not connected");
        }
    }
}
1 Like

@alejandronop a couple of questions:

  1. What lengths of delays did you add? Perhaps try a few milliseconds, long enough to separate the messages, but not long enough to hang the Core.
  2. When you say it runs in an ‘infinite loop’, what do you mean? If you put code to flash an LED in the loop, does the code continue to run, or does it hang?

Thanks for answering so fast :smiley:

  1. From 1 to 5 milliseconds.

  2. The code above, does not close the client with client.stop(), and continues to enter (client == true)

When I make a request with curl, client should be true and enter the IF (client == true), and then with client.stop() would have to no longer enter. And that does not happen.

I think I have identified the problem: The implemention of TCPServer is actually giving you a clone of connected TCPClient. It acts kind of like the hidden original, but not quite well.

I have a proof of concept fix locally, but it uses pointers and I’m not sure if that is “Arduino-style”:

client->println("HTTP/1.1 200 OK");

One way to hide may be an extra helper class that is used instead of TCPClient (that extra class would only have the pointer and redirect commads to it), or maybe the client pointer can be included inside the TCPServer then these prints would be like:

server.println("HTTP/1.1 200 OK");

I tried the example TCPServer, and also does strange things.
When I make a connection to port 23 and send one single character, make a loop that prints the same character.
Apparently client.read() function does not clear the buffer to read the next byte.

Also something strange happens with the connections, accepts the first connection, the second does not respond and accepts the third and fourth, then does not respond more connections. Forcing restart the core

Again sorry for my English

// EXAMPLE USAGE

// telnet defaults to port 23
TCPServer server = TCPServer(23);

void setup()
{
    // start listening for clients
    server.begin();

    Serial.begin(9600);

    delay(1000);

    Serial.println(Network.localIP());
    Serial.println(Network.subnetMask());
    Serial.println(Network.gatewayIP());
    Serial.println(Network.SSID());
}

void loop()
{
  // if an incoming client connects, there will be bytes available to read:
  TCPClient client = server.available();
  if (client == true) 
  {
      // read bytes from the incoming client and write them back
      // to any clients connected to the server:
      server.write(client.read());
  }
}

Thanks guys - I’ll add it to our backlog to take a look at this.

1 Like

There is definitely a problem witch client.read(). Also experiencing similar problem.

1 Like

We’re rolling out some new code later today that includes some improvements to tcpclient, so I’m hoping that will help

Update to the TCPServer thread in general. I looked into this in response to a question from new user @Cretcheu.

The problem with the previous example code (which we should still get working) is that the call to TCPServer::available() constructs a new TCPClient when a currently connected client has no bytes available. I have posted new TCPServer example code that works with the current :spark: TCPServer implementation.

The most important change is a slightly different loop that only calls server.available() when needed rather than every time:

if (client.connected()) {
    while (client.available()) {
        server.write(client.read());
    }
} else {
    client = server.available();
}

I can flash this example from the web IDE, connect from my laptop using telnet, and get results echoed exactly as intended.

2 Likes

Thanks for fixit it :smile:

I gave the new server code a whirl and it’s still not working for me. Here is the code I’m using:

int LED = D1;
int TILT = A0;
int val = 0;

TCPServer server = TCPServer(4444);
TCPClient client;

void setup() {
    // start listening for clients
    server.begin();

    Serial.begin(9600);
    
    pinMode(LED, OUTPUT);

    delay(1000);

    Serial.println(Network.localIP());
    Serial.println(Network.subnetMask());
    Serial.println(Network.gatewayIP());
    Serial.println(Network.SSID());
}

void loop() {
    //get the current value of the tilt sensor
    val = analogRead(TILT);
    
    //use the debug LED to show things are still working
    analogWrite(LED, val/16);
    
    if(client.connected()) {
      // echo all available bytes back to the client
      while (client.available()) {
        server.print(val);
      }
    } 
    else {
      // if no client is yet connected, check for a new connection
      client = server.available();
    }
    
    //fast fast!
    delay(20);
}

I have an LED connected to the tilt sensor so that I know when it crashes (basically when a new connection comes in…).

Probably doesn’t help them I’m constantly getting the green flashing LED of death all the time as well :frowning:

Thanks for helping Zachary.

Now it does well, but not stop client on disconnect.
even with client.stop(); still client.connected() == true, and you can not connect any other client.
I tried also with client.flush(); without success

on the other hand, with this change, we can have 2 listening ports?

Hello Zachary.

I still can not stop connections.
client not disconnect.

Any idea what is happening?

@satishgn is currently working on further improvements to TCPClient and TCPServer, so hopefully these will resolve the issues very soon.

1 Like

I am experiencing the same behavior with TCPServer as @lejandronop, is there a fix soon for this?

I strongly believe current TCPServer not working stable with latest code
(I am using Web build code)
I used the example from doc page to enable server on port 23. When I used the code as is, it work when connecting to Telnet.
But once combine with other part of the code, the system stop working.
Below is what I discover

  1. If remove the line to wait for serial port Serial.available(), TCPServer will not able to connect client. However, when I put in a 15 seconds delay (about the time I start terminal), then it works.
  2. Once TCPServer is called, all the Spark functions will not work (Spark.publish, Spark.variable, Spark.function) anymore.
  3. Remote Flashing will not work anymore

I will need help to confirm my finding.

1 Like

I am still hoping for a solution or suggestion. Does anyone have some sample code which can be shared how to make TCPServer works together with Spark cloud functions ?

Just wondering if there has been any progress on this matter

@wtpaul,

May I know what issues you are facing? I would love to replicate it as part of the agenda I hope to test with some free time :slight_smile:

I want the spark to be a TCP server. When a client connects; the spark delivers a short HTML string and then disconnects.
This work 100% for the first connection but never for a second connection

int			analogvalue         =  0;
TCPServer		myTCPserver         =  TCPServer(80);
TCPClient		myTCPclient;
char			szHTML[]            =  "sparkenv";
/*********************************************************************************************************
 *********************************************************************************************************/
void setup() {
	pinMode(PIN_LED_SPARK, OUTPUT);
	pinMode(PIN_LED_IO, OUTPUT);
	pinMode(PIN_POT, INPUT);
	pinMode(PIN_SW, INPUT);

	Serial1.begin(comm_uart_baud);          //tx rx serial port
	Serial1.println("Connect USB now");
	Serial.begin(comm_usb_baud);            //USB serial port
	while(!Serial.available()) SPARK_WLAN_Loop();

	Spark.disconnect();

	myTCPserver.begin();

	print_details();
	Serial.println("Loop -");
	Serial1.println("Loop -");
}

void loop() {

	comms_usb_menu();

	if (Serial1.available()){
		char inByte = Serial1.read();
		Serial1.print(inByte);		//echo back out of port
	}


	digitalWrite(PIN_LED_SPARK, LOW);
	if(myTCPclient.connected()){
		Serial1.println("Con    ");
		if(myTCPclient.available()){
			Serial1.print("\rClient avail...");
			Serial1.print(Time.timeStr());
			myTCPclient.write(szHTML);
			delay(10);
			myTCPclient.flush();
			delay(100);
			myTCPclient.stop();
			Serial1.print("\rClient Stop!...");
			Serial1.print(Time.timeStr());
		}
	}
	else {
		Serial1.print("\rNot Con");
		myTCPclient = myTCPserver.available();
	}
	digitalWrite(PIN_LED_SPARK, HIGH);

}

1 Like