1

I'm implementing a WiFi HTML web server using the WiFiNINA library, an Adafruit Airlift ESP32 coprocessor, and a Teensy 3.5. It's starting to work, but I have a couple of questions. This simplified code will illustrate the first.

#include <WiFiNINA.h>
#include "Wifi_names.h"

WiFiServer server(80);

void error (const char *msg) {
   Serial.println(msg);
   while (1) ; }

void setup(void) {
   Serial.begin(115200);
   while (!Serial) ;
   WiFi.setPins(19, 20, 21, -1, &SPI);
   if (WiFi.status() == WL_NO_SHIELD) error("no Wifi shield");
   Serial.print("ESP32 firmware version: "); Serial.println(WiFi.firmwareVersion());
   WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
   while (WiFi.status() != WL_CONNECTED) ;
   Serial.print("connected, IP address is ");
   server.begin();
   Serial.println(WiFi.localIP()); }

void show_client(const char *msg, WiFiClient *pclient) {
   Serial.print(msg); Serial.print(":");
   if (*pclient) {
      Serial.print(" IP "); Serial.print(pclient->remoteIP());
      Serial.print(" port "); Serial.print(pclient->remotePort()); }
   else Serial.print("none");
   Serial.println(); }

void check_for_another_client(const char *msg) {
   WiFiClient newClient;
   newClient = server.available();
   show_client(msg, &newClient); }

void loop(void) {
   WiFiClient client;
   while (!(client = server.available())) ;
   Serial.print("\n time: "); Serial.println((float)millis()/1000);
   show_client("client 1", &client);
   check_for_another_client("client 2");
   while (client.available() == 0) ;  // wait for data
   check_for_another_client("client 3");
   Serial.print("client 1 data read: "); Serial.println(client.read(), HEX); // read the data
   check_for_another_client("client 4");
   while (client.available()) client.read(); // flush the rest of the input
   delay(1000);
   client.stop(); // abort the connection
}

The output is:

ESP32 firmware version: 1.2.2
connected, IP address is 192.168.86.35

 time: 43.22
client 1: IP 192.168.86.32 port 62346
client 2: IP 192.168.86.32 port 62346
client 3:none
client 1 data read: 47
client 4:none

The question is: why does server.available() continue to say that I have new connections until there is some data available on the connection it already gave me? What if a second connection arrives after the 3-way TCP connection establishment handshake (SYN, ACK/SYN, ACK) but before any data arrives? How do I get that second connection?

The second question, which is related, is illustrated by the Sniffer trace of that transaction:

179 *REF*     192.168.86.32  192.168.86.35  TCP  66  62346 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1
180 0.000239  192.168.86.32  192.168.86.35  TCP  66  62347 → 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1
183 0.039352  192.168.86.35  192.168.86.32  TCP  58  80 → 62346 [SYN, ACK] Seq=0 Ack=1 Win=5744 Len=0 MSS=1436
184 0.039431  192.168.86.32  192.168.86.35  TCP  54  62346 → 80 [ACK] Seq=1 Ack=1 Win=64240 Len=0
185 0.039602  192.168.86.32  192.168.86.35  HTTP 488 GET / HTTP/1.1 
195 0.278592  192.168.86.35  192.168.86.32  TCP  54  80 → 62346 [ACK] Seq=1 Ack=435 Win=5310 Len=0
197 1.053036  192.168.86.35  192.168.86.32  TCP  54  80 → 62346 [FIN, ACK] Seq=1 Ack=435 Win=5310 Len=0
198 1.053146  192.168.86.32  192.168.86.35  TCP  54  62346 → 80 [ACK] Seq=435 Ack=2 Win=64240 Len=0
199 1.053600  192.168.86.32  192.168.86.35  TCP  54  62346 → 80 [FIN, ACK] Seq=435 Ack=2 Win=64240 Len=0
200 1.060248  192.168.86.35  192.168.86.32  TCP  54  80 → 62346 [ACK] Seq=2 Ack=436 Win=5309 Len=0

The request is from the Chrome browser. As you can see, it tries to establish two simultaneous TCP connections from two different source ports, 62346 and 62347, because it will use the second one for embedded images. But WiFiMINA never accepts that connection with the 3-way handshake, and never gives it to me. Chrome will resend the second SYN packet three seconds later, but as long as the first connection is still active, WiFiMINA continues to ignore it.

How can you accept two simultaneous TCP connections on different source ports from the same client? That's required for Chrome.

1 Answer 1

1

The server.available() in Arduino networking libraries returns always the first connected client. This is in contrary with ESP8266 and ESP32 WiFi libraries for Arduino. They flag the returned connection as claimed and don't return it again. If the WiFiClient on ESP goes out of scope it is closed. In Arduino libraries you must stop() the Client to close the connection and free the 'socket'.

The Arduino Ethernet library has a new function not adopted yet by the WiFi libraries. It is server.accept(). It marks the connection as accepted and the next call doesn't return the same client. The sketch is still responsible to call stop(). The use of accept() is demonstrated in AdvancedChatServer example of the Ethernet library 2.00.

What you can do? Get the connection (WiFiClient), handle the request, send the response and stop() the connection. Then handle the next Client. Set Expires header to let browser cache the static files.

4
  • "The server.available() in Arduino networking libraries returns always the first connected client." That doesn't seem to be the case for WiFiMINA. It's true the first time I call it in my example after connection ("Client 2"), but then as soon as data is available on the connection, server.available() returns zero. Aug 27, 2019 at 21:18
  • Your suggestion to "...handle the request, send the response and stop()" won't work for Chrome, because by that time the library has already ignored the SYN packet establishing the second connection. Besides, Chrome expects both connections to be open at the same time. That's a totally legitimate use of the TCP/IP protocol. Aug 27, 2019 at 21:26
  • but the TCP listening socket is on the ESP32. it should handle the TCP part of establishing the TCP connection. and then the connection should wait until the sketch gets to it
    – Juraj
    Aug 28, 2019 at 5:22
  • I agree, it should. But it doesn't seem to. Notice that it never responds to packet 180, which is trying to establish a connection from port 62347. Is there anything I could be doing wrong that causes it not to? Aug 28, 2019 at 5:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.