From ee6548260f214951a627486599cf1b2d626aeef7 Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Thu, 23 Oct 2025 16:56:34 +0200 Subject: [PATCH 1/2] Ethernet lib: add AdvancedChatServer example --- .../AdvancedChatServer/AdvancedChatServer.ino | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino diff --git a/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino b/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino new file mode 100644 index 00000000..a9c8a27e --- /dev/null +++ b/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino @@ -0,0 +1,126 @@ +/* + Advanced Chat Server + + A more advanced server that distributes any incoming messages + to all connected clients but the client the message comes from. + To use, telnet to your device's IP address and type. + + Usage: + 1. Upload this sketch to your board. + 2. Make sure your board is connected to the network and note its IP address. + 3. From a computer on the same network, open a terminal and connect via Telnet: + + - On macOS or Linux (using netcat if telnet is not available): + telnet 23 + # or, if telnet is missing: + nc 23 + + - On Windows (Command Prompt): + telnet 23 + # If 'telnet' is not recognized, enable it in "Windows Features". + + 4. Type a message and press Enter. + Your message will be broadcast to all connected clients except you. + + Example: + telnet 192.168.1.177 23 + + Press CTRL + ] then 'quit' to exit Telnet. + + */ + +#include "ZephyrServer.h" +#include "ZephyrClient.h" +#include "ZephyrEthernet.h" + +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +IPAddress ip(192, 168, 2, 9); // Un IP libero nella subnet 192.168.2.x +IPAddress myDns(192, 168, 2, 1); // Di solito si usa il gateway come DNS +IPAddress gateway(192, 168, 2, 1); // IP del bridge/router +IPAddress subnet(255, 255, 255, 0); // Subnet mask della rete + +// telnet defaults to port 23 +ZephyrServer server(23); + +ZephyrClient clients[8]; + +void setup() { + // start serial port: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // in Zephyr system check if Ethernet is ready before proceeding to initialize + Serial.print("Waiting for link on"); + while (Ethernet.linkStatus() != LinkON) { + Serial.print("."); + delay(100); + } + Serial.println(); + + // initialize the Ethernet device + Ethernet.begin(ip, myDns, gateway, subnet); + + // Check for Ethernet hardware present + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println("Ethernet cable is not connected."); + } + + // start listening for clients + server.begin(); + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // check for any new client connecting, and say hello (before any incoming data) + ZephyrClient newClient = server.accept(); + if (newClient) { + for (byte i=0; i < 8; i++) { + if (!clients[i]) { + Serial.print("We have a new client #"); + Serial.println(i); + newClient.print("Hello, client number: "); + newClient.println(i); + // Once we "accept", the client is no longer tracked by EthernetServer + // so we must store it into our list of clients + clients[i] = newClient; + break; + } + } + } + + // check for incoming data from all clients + for (byte i=0; i < 8; i++) { + if (clients[i] && clients[i].available() > 0) { + // read bytes from a client + byte buffer[80]; + int count = clients[i].read(buffer, 80); + Serial.println(count); + // write the bytes to all other connected clients + for (byte j=0; j < 8; j++) { + if (j != i && clients[j].connected()) { + clients[j].write(buffer, count); + } + } + } + } + + // stop any clients which disconnect + for (byte i=0; i < 8; i++) { + if (clients[i] && !clients[i].connected()) { + Serial.print("disconnect client #"); + Serial.println(i); + clients[i].stop(); + } + } +} \ No newline at end of file From 21f770e9551fd29e2d662d1ffbf8eb5000de9d49 Mon Sep 17 00:00:00 2001 From: Leonardo Cavagnis Date: Thu, 23 Oct 2025 16:57:07 +0200 Subject: [PATCH 2/2] Socket wrapper: fix destructor and check connected --- libraries/SocketWrapper/SocketWrapper.h | 3 --- libraries/SocketWrapper/ZephyrClient.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/SocketWrapper/SocketWrapper.h b/libraries/SocketWrapper/SocketWrapper.h index c9af9ff7..5dcff627 100644 --- a/libraries/SocketWrapper/SocketWrapper.h +++ b/libraries/SocketWrapper/SocketWrapper.h @@ -22,9 +22,6 @@ class ZephyrSocketWrapper { } ~ZephyrSocketWrapper() { - if (sock_fd != -1) { - ::close(sock_fd); - } } bool connect(const char *host, uint16_t port) { diff --git a/libraries/SocketWrapper/ZephyrClient.h b/libraries/SocketWrapper/ZephyrClient.h index 37ee7401..1092ef5e 100644 --- a/libraries/SocketWrapper/ZephyrClient.h +++ b/libraries/SocketWrapper/ZephyrClient.h @@ -40,7 +40,18 @@ class ZephyrClient : public arduino::Client, ZephyrSocketWrapper { return ret; } #endif + uint8_t connected() override { + if (sock_fd == -1) return false; + + uint8_t buf; + int ret = ::recv(sock_fd, &buf, 1, MSG_PEEK | MSG_DONTWAIT); + if (ret == 0) { + _connected = false; + ::close(sock_fd); + sock_fd = -1; + return false; + } return _connected; }