# How to Test TCP Server Multi Socket Example
## Step 1: Prepare software
The following serial terminal program and TCP/UDP test tool are required for the TCP Server Multi Socket example test, download and install from below links.
- [Tera Term][link-tera_term]
- [Hercules][link-hercules]
## Step 2: Prepare hardware
1. Connect the WIZnet Ethernet chip (W5500 or W6300) to the ESP32-S3 board over SPI, following the pin table in [Step 3](#step-3-setup-tcp-server-multi-socket-example).
2. Connect an Ethernet cable from the module's RJ45 port to your PC or network.
3. Connect the ESP32-S3 board to your PC with a USB cable.
![][link-hardware]
## Step 3: Setup TCP Server Multi Socket Example
### Chip and SPI configuration
Set the target and open menuconfig:
```bash
idf.py set-target esp32s3
idf.py menuconfig
```
Select **Component config**.
![][link-config_main]
Select **WIZnet WSM Driver** under Component config.
![][link-config_component]
Choose the WIZnet chip, and check the per-socket buffer size. SPI host, clock, and pins follow the selected chip automatically. In this example, SPI2 of the ESP32-S3 is used at 33 MHz.
![][link-config_wiz_toe]
> This example ships with **W6300** selected by default (`sdkconfig.defaults`). Switch to W5500 under `Component config -> WIZnet WSM Driver -> WIZnet chip` if needed.
**W5500 wiring (standard SPI)**
| W5500 | ESP32-S3 Pin |
|-------|--------------|
| MISO | 13 |
| MOSI | 11 |
| SCLK | 12 |
| CS | 10 |
| RESET | 9 |
| INT | 14 |
**W6300 wiring (QSPI)**
| W6300 | ESP32-S3 Pin |
|---------|--------------|
| D0 (MOSI) | 11 |
| D1 (MISO) | 13 |
| D2 (IO2) | 14 *(Quad mode only)* |
| D3 (IO3) | 9 *(Quad mode only)* |
| SCLK | 12 |
| CS | 10 |
| RESET | 21 |
| INT | 8 |
### Network configuration
All example settings live in `examples/tcp_server_multi_socket/inc/net_config.h`. The SPI wiring is **not** here — it comes from the component Kconfig shown above.
```cpp
#define NET_MAC_ADDR {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56} // MAC address
#define NET_IP_ADDR {192, 168, 11, 2} // IP address
#define NET_SUBNET_MASK {255, 255, 255, 0} // Subnet Mask
#define NET_GATEWAY {192, 168, 11, 1} // Gateway
#define NET_DNS_ADDR {8, 8, 8, 8} // DNS server
```
### Wi-Fi configuration
This example runs the **same echo server on the WIZnet chip and on Wi-Fi at the same time**, so fill in your AP credentials in the same file:
```cpp
#define WIFI_SSID "your-ssid"
#define WIFI_PASS "your-password"
```
Leaving the placeholders in place is harmless: the Wi-Fi side simply keeps retrying the connection and the Ethernet side is unaffected.
### Server port configuration
Each listener binds its own TCP port, `PORT_BASE + index`. The WIZnet chip cannot have several hardware sockets listening on the same port, so the listeners are spread across consecutive ports — this matches the original WIZnet-PICO-C example.
```cpp
#define MULTI_SOCKET_PORT_BASE 5000 // Ethernet: 5000..5007
#define WIFI_MULTI_SOCKET_PORT_BASE 5100 // Wi-Fi: 5100..5107
#define MULTI_SOCKET_COUNT 8
```
`MULTI_SOCKET_COUNT` is 8 to match the chip's 8 hardware sockets. Each listener costs one task on **both** interfaces, so lower it if you are short on RAM. The Wi-Fi side needs one lwIP socket per listener plus one per accepted connection, which is why `sdkconfig.defaults` raises `CONFIG_LWIP_MAX_SOCKETS` to 16.
## Step 4: Build
After completing the setup, build the project.
```bash
idf.py build
```
![][link-build_log]
## Step 5: Upload and Run
Flash the firmware and open the serial monitor. Replace the port with your board's serial port.
```bash
idf.py -p COMx flash monitor
```
On Linux/macOS:
```bash
idf.py -p /dev/ttyUSB0 flash monitor
```
If flashing succeeds, the assigned IP and the multi-socket server startup log appear in the terminal. Both interfaces come up independently, so the Wi-Fi lines may appear after the Ethernet ones.
```
wiztoe_net: TOE up: 192.168.11.2 (WIZnet hardware TCP/IP)
multi_socket: [eth] waiting for link...
multi_socket: [eth#0] listening on port 5000
multi_socket: [eth#1] listening on port 5001
multi_socket: [eth] 8/8 listeners up on ports 5000-5007
wifi: got IP 192.168.0.42
multi_socket: [wifi] 8/8 listeners up on ports 5100-5107
```
![][link-run_socket_open]
Open Hercules, select the **TCP Client** tab, enter the device IP `192.168.11.2` and port `5000`, then connect. Open several Hercules windows (or several TCP Client tabs) and connect each one to a **different port** (`5000`, `5001`, `5002`, …) at the same IP to use multiple sockets at once.
![][link-run_hercules]
To test the Wi-Fi side as well, use the IP the `wifi: got IP` line reported and ports `5100`, `5101`, … instead.
As each client connects, the device prints the interface, listener index and peer address, for example:
```
multi_socket: [eth#0] connected - 192.168.11.100:50312
multi_socket: [eth#1] connected - 192.168.11.101:50315
```
Send data from each connected Hercules window. The device echoes the same data back to the sender independently, and logs the listener, port and message:
```
multi_socket: [eth#0] port 5000 message:hello
multi_socket: [eth#1] port 5001 message:world
```
![][link-run_loopback]
Confirm that every connection echoes its own data back without interfering with the others.
## Appendix
- **Number of simultaneous clients:** On Ethernet the device serves as many connections as the chip has hardware sockets (8). Each listener runs in its own task and blocks in `accept()`/`recv()`, so the connections do not interfere with each other. The Wi-Fi side serves the same number over the ESP32-S3's own LwIP stack.
- **How one server drives two interfaces:** the echo logic in `src/multi_socket.c` calls BSD sockets through a vtable. For Ethernet that vtable is the plain `lwip_*` set, which the `wsm_driver` component redirects to the chip's hardware sockets at link time (`-Wl,--wrap`, `CONFIG_WSM_DRIVER_SOCKET_WRAP`); for Wi-Fi it is the un-wrapped `__real_lwip_*` set in `src/wifi_multi_socket.c`, which reaches the software LwIP stack. The application code is identical for both.
- **Ethernet only:** remove the `multi_socket_start("wifi", ...)` call (and `wifi_net_init`) from `main/main.c`.
- **W6300 QSPI mode:** Quad mode (4-bit) requires the extra D2/D3 lines wired and selected in `Component config -> WIZnet WSM Driver -> W6300 QSPI mode`. Single mode uses the same 4-wire wiring as W5500.
<!-- Link -->
[link-tera_term]: https://osdn.net/projects/ttssh2/releases/
[link-hercules]: https://www.hw-group.com/software/hercules-setup-utility
[link-hardware]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/hardware.png
[link-config_main]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/config_main.png
[link-config_component]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/config_component.png
[link-config_wiz_toe]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/config_wiz_toe.png
[link-build_log]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/build_log.png
[link-run_socket_open]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/run_socket_open.png
[link-run_hercules]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/run_hercules.png
[link-run_loopback]: https://raw.githubusercontent.com/Wiznet/wsm_driver/main/static/image/tcp_server_multi_socket/run_loopback.png
To create a project from this example, run:
idf.py create-project-from-example "wiznet/wsm_driver=1.1.0:tcp_server_multi_socket"