From 6038dd6b42d4045b2591e2e80b8de05ba386a3ed Mon Sep 17 00:00:00 2001 From: Jens B Date: Sun, 15 Mar 2020 13:17:41 +0100 Subject: [PATCH 1/3] EthernetClientStream write buffer - reduce network overhead by buffering writes --- utility/EthernetClientStream.h | 49 ++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/utility/EthernetClientStream.h b/utility/EthernetClientStream.h index 1b7d2e29..b131d92c 100644 --- a/utility/EthernetClientStream.h +++ b/utility/EthernetClientStream.h @@ -14,7 +14,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated June 18th, 2016 + Last updated March 10th, 2020 */ #ifndef ETHERNETCLIENTSTREAM_H @@ -28,6 +28,17 @@ #define MILLIS_RECONNECT 5000 +// If defined and set to a value higher than 1 all single bytes writes +// will be buffered until one of the following conditions is met: +// 1) write buffer full +// 2) any call to read(), available(), maintain(), peek() or flush() +// By combining the buffered bytes into a single TCP frame this feature will significantly +// reduce the network and receiver load by the factor 1/(1/20 + 1/bufferedSize). +// Buffer sizes up to 80 have been tested successfully. Note that higher buffer values +// may cause slight delays between an event and the network transmission. +#define WRITE_BUFFER_SIZE 40 + + class EthernetClientStream : public Stream { public: @@ -47,6 +58,10 @@ class EthernetClientStream : public Stream uint16_t port; bool connected; uint32_t time_connect; +#ifdef WRITE_BUFFER_SIZE + uint8_t writeBuffer[WRITE_BUFFER_SIZE]; + uint8_t writeBufferLength; +#endif bool maintain(); void stop(); }; @@ -64,6 +79,9 @@ EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IP host(host), port(port), connected(false) +#ifdef WRITE_BUFFER_SIZE + , writeBufferLength(0) +#endif { } @@ -94,7 +112,20 @@ void EthernetClientStream::flush() size_t EthernetClientStream::write(uint8_t c) { +#ifdef WRITE_BUFFER_SIZE + if (connected) { + // buffer new byte and send buffer when full + writeBuffer[writeBufferLength++] = c; + if (writeBufferLength >= WRITE_BUFFER_SIZE) { + return maintain()? 1 : 0; + } + return 1; + } else { + return 0; + } +#else return maintain() ? client.write(c) : 0; +#endif } void @@ -113,14 +144,25 @@ EthernetClientStream::stop() { client.stop(); connected = false; +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif time_connect = millis(); } bool EthernetClientStream::maintain() { - if (client && client.connected()) + if (client && client.connected()) { +#ifdef WRITE_BUFFER_SIZE + // send buffered bytes + if (writeBufferLength) { + client.write(writeBuffer, writeBufferLength); + writeBufferLength = 0; + } +#endif return true; + } if (connected) { stop(); @@ -132,6 +174,9 @@ EthernetClientStream::maintain() time_connect = millis(); DEBUG_PRINTLN("Connection failed. Attempting to reconnect..."); } else { +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif DEBUG_PRINTLN("Connected"); } } From 9bb317d6926da01d6af22c0152a594538a65f659 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sat, 4 Apr 2020 19:48:16 +0200 Subject: [PATCH 2/3] EthernetServerStream write buffer - reduce network overhead by buffering writes --- utility/EthernetServerStream.h | 38 ++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/utility/EthernetServerStream.h b/utility/EthernetServerStream.h index 56f541e9..c1300c48 100644 --- a/utility/EthernetServerStream.h +++ b/utility/EthernetServerStream.h @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated July 10th, 2017 + Last updated March 21st 2020 */ #ifndef ETHERNETSERVERSTREAM_H @@ -23,6 +23,17 @@ //#define SERIAL_DEBUG #include "firmataDebug.h" +// If defined and set to a value higher than 1 all single bytes writes +// will be buffered until one of the following conditions is met: +// 1) write buffer full +// 2) any call to read(), available(), maintain(), peek() or flush() +// By combining the buffered bytes into a single TCP frame this feature will significantly +// reduce the network and receiver load by the factor 1/(1/20 + 1/bufferedSize). +// Buffer sizes up to 80 have been tested successfully. Note that higher buffer values +// may cause slight delays between an event and the network transmission. +#define WRITE_BUFFER_SIZE 40 + + class EthernetServerStream : public Stream { public: @@ -39,6 +50,10 @@ class EthernetServerStream : public Stream IPAddress localip; uint16_t port; bool connected; +#ifdef WRITE_BUFFER_SIZE + uint8_t writeBuffer[WRITE_BUFFER_SIZE]; + uint8_t writeBufferLength; +#endif bool maintain(); void stop(); @@ -58,6 +73,9 @@ EthernetServerStream::EthernetServerStream(IPAddress localip, uint16_t port) : localip(localip), port(port), connected(false) +#ifdef WRITE_BUFFER_SIZE + , writeBufferLength(0) +#endif { } @@ -65,7 +83,17 @@ bool EthernetServerStream::connect_client() { if ( connected ) { - if ( client && client.connected() ) return true; + if ( client && client.connected() ) + { +#ifdef WRITE_BUFFER_SIZE + // send buffered bytes + if (writeBufferLength) { + client.write(writeBuffer, writeBufferLength); + writeBufferLength = 0; + } +#endif + return true; + } stop(); } @@ -73,6 +101,9 @@ bool EthernetServerStream::connect_client() if ( !newClient ) return false; client = newClient; connected = true; +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif DEBUG_PRINTLN("Connected"); return true; } @@ -126,6 +157,9 @@ EthernetServerStream::stop() client.stop(); } connected = false; +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif } bool From 2841bbd975b63582a73bcabc13f14a87132f3944 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sat, 4 Apr 2020 19:49:54 +0200 Subject: [PATCH 3/3] WiFiClientStream and WiFiServerStream write buffer - reduce network overhead by buffering writes --- utility/WiFiClientStream.h | 27 +++++++++++++++++++++++---- utility/WiFiServerStream.h | 18 +++++++++++++++++- utility/WiFiStream.h | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/utility/WiFiClientStream.h b/utility/WiFiClientStream.h index 7fd30af6..387ddab2 100644 --- a/utility/WiFiClientStream.h +++ b/utility/WiFiClientStream.h @@ -20,7 +20,7 @@ published under the same license. - Last updated April 23rd, 2016 + Last updated March 21st, 2020 */ #ifndef WIFI_CLIENT_STREAM_H @@ -43,7 +43,17 @@ class WiFiClientStream : public WiFiStream { if ( _connected ) { - if ( _client && _client.connected() ) return true; + if ( _client && _client.connected() ) + { +#ifdef WRITE_BUFFER_SIZE + // send buffered bytes + if (writeBufferLength) { + _client.write(writeBuffer, writeBufferLength); + writeBufferLength = 0; + } +#endif + return true; + } stop(); } @@ -58,9 +68,15 @@ class WiFiClientStream : public WiFiStream { _time_connect = millis(); } - else if ( _currentHostConnectionCallback ) + else { - (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif + if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); + } } } } @@ -97,6 +113,9 @@ class WiFiClientStream : public WiFiStream } } _connected = false; +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif _time_connect = millis(); } diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index 1404b056..6bcbab7e 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -42,7 +42,17 @@ class WiFiServerStream : public WiFiStream { if ( _connected ) { - if ( _client && _client.connected() ) return true; + if ( _client && _client.connected() ) + { +#ifdef WRITE_BUFFER_SIZE + // send buffered bytes + if (writeBufferLength) { + _client.write(writeBuffer, writeBufferLength); + writeBufferLength = 0; + } +#endif + return true; + } stop(); } @@ -51,6 +61,9 @@ class WiFiServerStream : public WiFiStream if ( !newClient ) return false; _client = newClient; _connected = true; +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif if ( _currentHostConnectionCallback ) { (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); @@ -100,6 +113,9 @@ class WiFiServerStream : public WiFiStream } } _connected = false; +#ifdef WRITE_BUFFER_SIZE + writeBufferLength = 0; +#endif } }; diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 1ad44bbb..0c54ff6d 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -15,7 +15,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 23rd, 2016 + Last updated March 21st, 2020 */ #ifndef WIFI_STREAM_H @@ -27,6 +27,17 @@ #define HOST_CONNECTION_DISCONNECTED 0 #define HOST_CONNECTION_CONNECTED 1 +// If defined and set to a value higher than 1 all single bytes writes +// will be buffered until one of the following conditions is met: +// 1) write buffer full +// 2) any call to read(), available(), maintain(), peek() or flush() +// By combining the buffered bytes into a single TCP frame this feature will significantly +// reduce the network and receiver load by the factor 1/(1/20 + 1/bufferedSize). +// Buffer sizes up to 80 have been tested successfully. Note that higher buffer values +// may cause slight delays between an event and the network transmission. +#define WRITE_BUFFER_SIZE 40 + + extern "C" { // callback function types typedef void (*hostConnectionCallbackFunction)(byte); @@ -38,6 +49,10 @@ class WiFiStream : public Stream WiFiClient _client; bool _connected = false; hostConnectionCallbackFunction _currentHostConnectionCallback; +#ifdef WRITE_BUFFER_SIZE + uint8_t writeBuffer[WRITE_BUFFER_SIZE]; + uint8_t writeBufferLength; +#endif //configuration members IPAddress _local_ip; // DHCP @@ -58,7 +73,11 @@ class WiFiStream : public Stream public: /** constructor for TCP server */ - WiFiStream(uint16_t server_port) : _port(server_port) {} + WiFiStream(uint16_t server_port) : +#ifdef WRITE_BUFFER_SIZE + writeBufferLength(0), +#endif + _port(server_port) {} /** constructor for TCP client */ WiFiStream(IPAddress server_ip, uint16_t server_port) : _remote_ip(server_ip), _port(server_port) {} @@ -218,7 +237,20 @@ class WiFiStream : public Stream inline size_t write(uint8_t byte) { +#ifdef WRITE_BUFFER_SIZE + if (connect_client()) { + // buffer new byte and send buffer when full + writeBuffer[writeBufferLength++] = byte; + if (writeBufferLength >= WRITE_BUFFER_SIZE) { + return maintain()? 1 : 0; + } + return 1; + } else { + return 0; + } +#else return connect_client() ? _client.write( byte ) : 0; +#endif } };