Welcome to ESP32 Core Board repository
6. TCP Client Experiment
TCP Client Experiment
TCP Client Experiment1. TCP Client Overview2. Core Concepts2.1 TCP Connection Lifecycle2.2 The "Packet Sticking" Problem of Stream Protocols2.3 write() vs print()3. Hardware Dependencies4. Project Architecture and Flow5. Source Code Analysis5.1 Configuration and Global Variables5.2 setup() — Establish TCP Connection5.3 loop() — Send and Receive6. Operation Flow6.1 Build and Flash6.2 Operation Steps6.3 Verification Methods7. Common Issues
1. TCP Client Overview
TCP (Transmission Control Protocol) is a connection-oriented, reliable, byte-stream transport layer protocol. It establishes connections through three-way handshake, ensuring data arrives in order and intact.
TCP is the foundation of IoT communication. Whether it's HTTP web requests, MQTT message publishing, OTA firmware upgrades, or database remote connections, they all rely on TCP's reliable transmission at the underlying layer. In industrial automation, smart home, and remote monitoring scenarios, devices report sensor data and receive control commands, requiring "no data loss, no order disruption" - this is TCP's core value. UDP is fast but unreliable; TCP's three-way handshake overhead is worth it for the end-to-end acknowledgment and retransmission mechanism, which is irreplaceable in most IoT scenarios.
In this experiment, ESP32-S3 acts as a TCP client to actively connect to the server, sending one data message per second and receiving server responses. The WiFiClient class encapsulates lwIP's TCP socket, with connection, sending, receiving, and disconnection detection all completed through simple method calls.
Typical Application Scenarios:
| Application Type | Example |
|---|---|
| HTTP Requests | Browser accessing web pages (HTTP is essentially TCP at the underlying layer) |
| Remote Control | SSH, Telnet remote terminals |
| Data Collection | Reliable sensor data upload |
| File Transfer | FTP, custom binary protocols |
2. Core Concepts
2.1 TCP Connection Lifecycle
A TCP client goes through 5 phases from connection to closure, each corresponding to a WiFiClient method:
xxxxxxxxxxconnect(ip, port) establish connection↓ underlying: three-way handshake SYN → SYN-ACK → ACK, blocking wait, returns true on successwrite / print send data↓ full-duplex: both parties can send/receive simultaneously, write sends raw bytes, print sends formatted textavailable() / read() receive data↓ available() returns number of readable bytes, non-blocking, returns 0 if no dataconnected() liveness check↓ returns false if remote endpoint has closed (received FIN/RST) or network timeoutstop() close connectionunderlying: four-way handshake FIN → ACK ← FIN → ACK, release socket resources
| Method | Function | Blocking? |
|---|---|---|
connect(ip, port) | Initiate three-way handshake, establish TCP connection | Yes |
write(buf, len) | Send raw bytes | No (writes to send buffer) |
print(str) | Send formatted text | No |
available() | Query number of readable bytes in receive buffer | No |
read(buf, len) | Read data from receive buffer | No |
connected() | Check if connection is alive | No |
stop() | Actively close connection (four-way handshake) | No |
2.2 The "Packet Sticking" Problem of Stream Protocols
TCP is a stream (Stream) protocol, unlike UDP which preserves message boundaries. If the sender does two write("Hello") and write("World"), the receiver may receive "HelloWorld" in one read() (packet sticking), or may receive three fragments "Hel", "loWor", "ld" (fragmentation). The application layer must define message boundaries itself (such as newline characters, length prefixes, etc.).
2.3 write() vs print()
| Function | Purpose | Applicable Scenario |
|---|---|---|
write(buf, len) | Send raw bytes | Binary protocols |
print(data) | Formatted text (numbers → strings) | HTTP, text protocols |
println(data) | print + \r\n at end | HTTP line endings |
3. Hardware Dependencies
Pure software experiment. Need to connect to router via WIFI-STA first, client and server must be on the same local area network.
4. Project Architecture and Flow
xxxxxxxxxxsetup()├─ connectWiFi()└─ client.connect(SERVER_IP, SERVER_PORT) // three-way handshakeloop()├─ if disconnected → stop() → mark for reconnect├─ client.write(send_buf) // send raw bytes├─ if client.available() → client.read() // non-blocking read└─ delay(1000)
5. Source Code Analysis
Complete source code: Source code → Arduino → 3.Network Communication → TCP_Client → TCP_Client.ino
5.1 Configuration and Global Variables
xxxxxxxxxxWiFiClient client;const char* SERVER_IP = "192.168.11.183";uint16_t SERVER_PORT = 8080;5.2 setup() — Establish TCP Connection
client.connect() initiates three-way handshake, returns true on success, returns false on failure (server not listening/firewall rejection).
xxxxxxxxxxvoid setup() { Serial.begin(115200); connectWiFi();
if (!client.connect(SERVER_IP, SERVER_PORT)) { Serial.println("Failed to connect to the server!"); return; } Serial.println("Server Connected Successfully!");}5.3 loop() — Send and Receive
xxxxxxxxxxvoid loop() { if (!client.connected()) { // detect disconnection Serial.println("TCP Server disconnected!"); client.stop(); delay(2000); ESP.restart(); return; }
client.write("ESP32 TCP Client Data"); // send raw bytes
if (client.available()) { // non-blocking read char buf[128]; int len = client.read(buf, sizeof(buf) - 1); buf[len] = '\0'; Serial.printf("Receive: %s\n", buf); } delay(1000);}
client.connected()returnsfalsewhen: server FIN received, RST received, or multiple retransmissions with no ACK timeout.ESP.restart()is used for overall reset and reconnect after disconnection—this is the cleanest approach.
6. Operation Flow
6.1 Build and Flash
Arduino flash process: See Arduino → 1. Before Development → 2. Build and Flash.
Modify server IP to actual address
First use network debugging assistant or TCP server program to listen on port 8080
Build and flash
6.2 Operation Steps
Step 1: Open network debugging assistant
, configure TCP server
Open network debugging assistant on PC, configure with following parameters:

| Parameter | Value |
|---|---|
| Protocol Type | TCP Server |
| Local IP Address | PC's LAN IP (e.g., 192.168.11.183) |
| Local Port | 8080 |
Click "Connect" button, network debugging assistant starts listening on TCP port 8080.
Step 2: Modify server IP in code, flash program
Open Arduino IDE, modify SERVER_IP in code to PC's actual LAN IP address, then compile and flash to ESP32-S3 development board.

Step 3: Open serial monitor, observe connection and send/receive
After flashing, open serial monitor (baud rate 115200), ESP32 will automatically connect to TCP server, after successful connection sends one data message per second and receives replies:
xxxxxxxxxx11:30:16.823 -> Connecting to WiFi: Yahboom2 (Attempt 1)11:30:17.877 -> ...11:30:18.885 -> WiFi Connected successfully!11:30:18.885 -> Device IP: 192.168.11.22911:30:18.885 -> Target Server: 192.168.11.183:808011:30:18.930 -> Server Connected Successfully!11:30:18.930 -> Send data: ESP32 TCP Client Data11:30:19.942 -> Send data: ESP32 TCP Client Data11:30:20.950 -> Send data: ESP32 TCP Client Data...

At this point, enter any content in the send area of network debugging assistant and send, serial monitor will print data received by ESP32.

Data interaction:

Step 4: Test disconnection detection
Close TCP server of network debugging assistant (click "Disconnect"). After ESP32 detects disconnection, it prints TCP Server disconnected!, automatically restarts after 2 seconds and attempts to reconnect.

6.3 Verification Methods
| Operation | Expected Result |
|---|---|
| Power on when server is online | Connection successful, send/receive once per second |
| Disconnect server | Print "disconnected", ESP.restart() resets and reconnects |
7. Common Issues
| Symptom | Cause | Solution |
|---|---|---|
connect() never returns | Firewall drops SYN packet with no response | Check server firewall settings |
| Received data stuck together | Inherent characteristic of TCP stream protocol | Add message boundary at application layer (e.g., \n separator) |
connected() returns true but write fails | Connection closed but not detected (half-open connection) | Enable TCP keepalive or periodic heartbeat |