TCPClient transfer rate

Hi all,

I am trying to benchmark the speed at which I can transfer data off of an Argon using TCPClient and a simple node.js TCP server to receive and save the data to a file. I’ve seen in other posts such as by @rickkas7 showing that speeds of up to 900KB/s or even 1MB/s are possible, but the max I can seem to achieve is around 45-55KB/s using the Argon.

I am able to use other tcp clients that aren’t particle devices, such as a node.js tcp client example and get much higher speeds, but no more than 55KB/s on the Argon. I have tried changing my buffer size and I get essentially the same results at 512 and 1024 B.

Since the Argon uses the ESP32 for wifi comms and communicates with the ESP32 via Serial, is it possible that the Serial data rate is the limiting factor here? I’ll include my device code below, and I can include my node server code as well in case anyone else wants to check their own results.

UPDATE: Using Ethernet instead of WiFi on the Argon I can reach speeds of 400KB/s which is certainly better, but still it’s basically 1/2 of the speed people claim to get over WiFi! I understand that gen3 devices communicate with the ethernet shield via SPI whereas WiFi through the ESP32 is done with Serial so regardless of the inherent advantages of wired over wireless I feel like this could be related (SPI vs Serial)

Thanks for any help/insight anyone can offer!

device code:

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

#define CACHE 1024

TCPClient client;

const byte host[] = {192, 168, 0, 110};
char buf[CACHE];

void setup() {

    Serial.begin(9600);
    waitUntil(Serial.isConnected);

    Serial.println("Starting WiFi...");

    WiFi.on();
    WiFi.connect();
    waitUntil(WiFi.ready);
    Serial.print("WiFi connected with IP: ");
    Serial.println(WiFi.localIP());

    Serial.println("Connecting to TCP Server...");

    int rc = client.connect(host, 8081);

    Serial.printf("Connect returned code: %d\n", rc);


    if (client.connected()) {

        Serial.print("Connected to : ");
        Serial.println(client.remoteIP());

        memset(buf, 'A', CACHE);

        for(int i = 0; i < 1000000; i += CACHE) {

            client.print(buf);
        }

        while(client.available() > 0) {

            Serial.print(client.read());

        }

        client.stop();
    } else {
        
        Serial.println("Connection failed!");
    }



}

void loop() {

}

server code: (excuse my sloppy work)

const net = require('net');
const port = 8081;
const host = '0.0.0.0';

var fs = require('fs');
var totalsize = 0;
var totaltime = 0;
var start = 0;
var end = 0;
var avgspeed = 0;


const server = net.createServer();
server.listen(port, host, () => {
    console.log('TCP Server is running on port ' + port + '.');
});


server.on('connection', function(sock) {
    
    totalsize = 0;
    currspeed = 0;
    start = process.hrtime();
    console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort);
    fs.unlinkSync("data.dat");
    var file = fs.createWriteStream("data.dat");
    sock.on('data', function(data) {

        file.write(data);
        totalsize += data.length;     
        end = process.hrtime(start);
        totaltime = end[0]+(end[1]/1000000000);
        avgspeed = (totalsize/1000)/(totaltime);
        process.stdout.write(avgspeed+' KB/s\n')      
        
    });

    sock.on('close', function(data) {
        end = process.hrtime(start);
        totaltime = end[0]+(end[1]/1000000000);
        avgspeed = (totalsize/1000)/(totaltime);
        file.close();
        console.info('Transfer time: %ds %dms', end[0], end[1] / 1000000);
        console.log('Avg speed: '+avgspeed+' KB/s');
        console.log('Total size: '+totalsize);
        console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort);
    });
});

I got around 57 Kbytes/sec sending on the Argon, sending in 512 byte chunks.

You can’t really compare the numbers from the Photon/P1 which use a completely different chipset.

Sending code:

#include "Particle.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

SerialLogHandler logHandler;

IPAddress serverAddr(192, 168, 2, 4);
int serverPort = 7200;
TCPClient client;
bool connected = false;

const size_t BUF_SIZE = 512;
uint8_t buf[BUF_SIZE];
size_t bytesSent = 0;

const unsigned long REPORT_TIME_MS = 10000;
unsigned long lastReport = 0;

void setup() {
	WiFi.connect();

	memset(buf, 'X', BUF_SIZE);
}

void loop() {
	if (WiFi.ready()) {
		if (connected) {
			if (client.connected()) {
				// Write data on connection
				int sent = client.write(buf, BUF_SIZE);
				if (sent > 0) {
					bytesSent += sent;
				}
			}
			else {
				// Reconnect on next loop
				connected = false;
				Log.info("socket disconnected");
			}
		}
		else {
			connected = client.connect(serverAddr, serverPort);
			if (connected) {
				Log.info("connected to %s:%d", serverAddr.toString().c_str(), serverPort);
			}
			else {
				Log.info("failed to connect to %s:%d", serverAddr.toString().c_str(), serverPort);
				delay(2000);
			}
		}
	}
	else {
		if (connected) {
			client.stop();
			Log.info("WiFi disconnected");
		}
	}
	if (millis() - lastReport >= REPORT_TIME_MS) {
		unsigned long elapsedSec = (millis() - lastReport) / 1000;

		if (elapsedSec > 0) {
			Log.info("sent %u bytes in %u sec., %u bytes/sec", bytesSent, elapsedSec, bytesSent / elapsedSec);
		}

		lastReport = millis();
		bytesSent = 0;
	}
}

I just sent it to nc (netcat) running as a server listener:

nc -l 7200 > /dev/null

Results:

0000020029 [app] INFO: sent 578048 bytes in 10 sec., 57804 bytes/sec
0000030038 [app] INFO: sent 584192 bytes in 10 sec., 58419 bytes/sec
0000040050 [app] INFO: sent 581120 bytes in 10 sec., 58112 bytes/sec
0000050056 [app] INFO: sent 583680 bytes in 10 sec., 58368 bytes/sec
0000060069 [app] INFO: sent 582656 bytes in 10 sec., 58265 bytes/sec
2 Likes

tThanks Rick, it seems I only saw your tests using the Photon previously and mistakenly assumed I should be able to get similar throughput on the Gen3 devices.

Have you tried a test like this over Ethernet on a gen3 device? I got approx 420KB/s maximum when I just tested it, at least the Ethernet adaptor uses SPI instead of Serial!

Thanks,
Addison