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.