Here’s my quick test. I have a Photon (0.4.9) and it’s running a TCPServer in the program below. It accepts a connection and receives 10 MB of data as fast as it can. It takes about 83 seconds or around 123 Kbytes/sec. Then it closes the connection and the process immediately repeats on a new connection. I let this go 30 times, for a total of 300 MB of data received by the Photon. No problems so far. I’m going to try a few other things to see if I can cause trouble.
#include "Particle.h"
const int MAX_CLIENTS = 5;
const int LISTEN_PORT = 7123;
const int CLIENT_BUF_SIZE = 1024;
const unsigned long INACTIVITY_TIMEOUT_MS = 30000;
const int CLOSE_AFTER_SIZE = 1024 * 1024 * 10; // 10 MB, set to -1 for unlimited
class ClientConnection {
public:
ClientConnection();
virtual ~ClientConnection();
void loop();
bool accept();
protected:
void clear();
void readRequest();
void writeData();
private:
unsigned char clientBuf[CLIENT_BUF_SIZE];
bool inUse;
int clientId;
TCPClient client;
int readOffset;
int writeOffset;
unsigned long lastUse;
unsigned char expectedChar;
unsigned long bytesRead;
time_t startTime;
};
String localIP;
TCPServer server(LISTEN_PORT);
ClientConnection clients[MAX_CLIENTS];
int nextClientId = 1;
void setup() {
Serial.begin(9600);
// From CLI, use something like:
// particle get test5 localip
// to get the IP address of the Photon (replace "test5" with your device name)
localIP = WiFi.localIP(); // localIP must be a global variable
Particle.variable("localip", localIP);
Serial.printlnf("server=%s:%d", localIP.c_str(), LISTEN_PORT);
server.begin();
}
void loop() {
// Handle any existing connections
for(int ii = 0; ii < MAX_CLIENTS; ii++) {
clients[ii].loop();
}
// Accept a new one if there is one waiting (and we have a free client)
for(int ii = 0; ii < MAX_CLIENTS; ii++) {
if (clients[ii].accept()) {
break;
}
}
}
ClientConnection::ClientConnection() : inUse(false) {
clear();
}
ClientConnection::~ClientConnection() {
}
void ClientConnection::loop() {
if (!inUse) {
return;
}
if (client.connected()) {
readRequest();
if (millis() - lastUse > INACTIVITY_TIMEOUT_MS) {
Serial.printlnf("%d: inactivity timeout", clientId);
client.stop();
clear();
}
}
else {
Serial.printlnf("%d: client disconnected", clientId);
client.stop();
clear();
}
}
bool ClientConnection::accept() {
if (inUse) {
return false;
}
client = server.available();
if (client.connected()) {
lastUse = millis();
inUse = true;
clientId = nextClientId++;
startTime = Time.now();
Serial.printlnf("%d: connection accepted", clientId);
}
return true;
}
void ClientConnection::clear() {
lastUse = 0;
readOffset = 0;
writeOffset = 0;
inUse = false;
expectedChar = 0;
bytesRead = 0;
}
void ClientConnection::readRequest() {
// Note: client.read returns -1 if there is no data; there is no need to call available(),
// which basically does the same check as the one inside read().
int count = client.read(clientBuf, CLIENT_BUF_SIZE);
if (count > 0) {
for(int ii = 0; ii < count; ii++) {
if (clientBuf[ii] != expectedChar) {
Serial.printlnf("%d: mismatch expected %02x got %02x index %d bytesRead %d, closing",
clientId, expectedChar, ii, bytesRead + ii);
client.stop();
clear();
break;
}
expectedChar++;
bytesRead++;
if (CLOSE_AFTER_SIZE > 0 && bytesRead >= CLOSE_AFTER_SIZE) {
time_t now = Time.now();
Serial.printlnf("%d: received %d bytes in %d sec, closing connection",
clientId, bytesRead, now - startTime);
client.stop();
clear();
break;
}
}
lastUse = millis();
}
}