Hi!
I’m using the built in tcp client to frequently write messages to and receive messages from a backend. However,
I just discovered that the write function seems to cause a leak.
Using programmer shield and debug output, I can see that my freeMemory sometimes decreases by about 1200 specifically during the call to that function. I print out freeMemory right before and right after, and that is where the drop happens, according to the freeMemory function.
The particle documentation says that there are two TCPClient::write methods:
-
client.write(val);
where val is a single byte to be written -
client.write(buf, len);
where buf is an array of bytes and len is the length of the buffer.
In my code, I use client.write(buf), and hand it an array of integers. Though it doesn’t match either of the documented usages, it seems to work; the messages are being sent successfully, and I am getting the responses I expect. BUT, there’s this memory leak…
Am I calling the method wrong? Is the documentation out of date? What is going on? Thanks in advance!
EDIT: here is an example program that works in a similar way to my program, but with less timing control and without doing anything with the response. I do not see the memory leak here.
#include "application.h" //needed when compiling spark locally
#define HOST_NAME "posttestserver.com"
#define HOST_PORT_NUMBER 80
using namespace std;
SYSTEM_MODE(MANUAL);
short BUFF_SIZE;
short num_retrys;
short num_bytes_rcvd;
char* request_buff;
char* response_buff;
TCPClient _tcp_client;
char _state;
const char STATE_INIT = 0;
const char STATE_SEND_MESSAGE = 1;
const char STATE_RECEIVE_RESPONSE = 2;
const char STATE_FINISH_RESTART = 3;
bool write_msg(char*& msg)
{
bool rslt = true;
if(!_tcp_client.connected())
{
rslt = _tcp_client.connect(HOST_NAME, HOST_PORT_NUMBER);
}
if(rslt == false)
{
Serial.println("Can't connect to server!");
}
else {
Serial.println("Writing message:");
Serial.println(msg);
short msg_len = strlen(msg);
Serial.print("freeMemory before write: ");
Serial.println(System.freeMemory());
short bytes_written = _tcp_client.write(msg);
Serial.print("freeMemory after write: ");
Serial.println(System.freeMemory());
rslt = (rslt && bytes_written == msg_len);
if(bytes_written != msg_len)
{
Serial.println("Error, bytes_written != msg_len");
}
}
return rslt;
}
void setup()
{
Serial.println("Main::Setup:: Waiting ...");
delay(2000);
BUFF_SIZE = 512;
num_retrys = 0;
request_buff = new char[BUFF_SIZE];
strcpy(request_buff, "");
response_buff = new char[2*BUFF_SIZE];
strcpy(response_buff, "");
_state = STATE_INIT;
num_bytes_rcvd = 0;
Serial.println("Turning on wifi module");
WiFi.on();
Serial.println("Attempting to connect to wifi");
WiFi.connect();
Serial.println("Checking connection");
while(!WiFi.ready()){
Serial.println("wifi connection failed, retrying ...");
delay(3000);
WiFi.connect();
}
Serial.println("WiFi connection succeeded!");
Serial.println("Attempting to connect to host");
_tcp_client.connect(HOST_NAME, HOST_PORT_NUMBER);
while(!_tcp_client.connected()){
Serial.println("host connection failed, retrying ... ");
delay(1000);
_tcp_client.connect(HOST_NAME, HOST_PORT_NUMBER);
}
Serial.println("Connected to host");
delay(2000);
}
void loop()
{
// Serial.printf("Free Memory: %d\n", System.freeMemory());
if(!_tcp_client.connected())
{
Serial.println("Disconnected during state machine, retrying...");
bool rslt = _tcp_client.connect(HOST_NAME, HOST_PORT_NUMBER);
if(!rslt)
return;
}
switch(_state){
case STATE_INIT: {
strcat(request_buff, "POST /post.php HTTP/1.1\r\n");
strcat(request_buff, "Host: ");
strcat(request_buff, HOST_NAME);
strcat(request_buff, "\r\n");
strcat(request_buff, "Connection: Keep-Alive\r\n");
strcat(request_buff, "Content-Length: 27\r\n");
strcat(request_buff, "\r\n");
strcat(request_buff, "field1=value1&field2=value2\r\n");
strcat(request_buff, "\r\n");
_state = STATE_SEND_MESSAGE;
break;
}
case STATE_SEND_MESSAGE: {
if(write_msg(request_buff))
{
_state = STATE_RECEIVE_RESPONSE;
}
else
{
Serial.println("Message send failed, delay then retrying");
num_retrys++;
Serial.print("num_retrys = ");
Serial.println(num_retrys);
delay(2000);
}
break;
}
case STATE_RECEIVE_RESPONSE: {
if(_tcp_client.available() > 0)
{
//get rid of anything we receive, don't care.
response_buff[num_bytes_rcvd] = _tcp_client.read();
num_bytes_rcvd++;
}
else {
response_buff[num_bytes_rcvd] = 0;
Serial.println("No more bytes to read from server");
Serial.print("Number of bytes received = ");
Serial.println(num_bytes_rcvd);
Serial.println("Content from server: ");
Serial.println(response_buff);
_state = STATE_FINISH_RESTART;
}
break;
}
case STATE_FINISH_RESTART: {
num_bytes_rcvd = 0;
strcpy(request_buff, "");
strcpy(response_buff, "");
delay(1000);
_state = STATE_INIT;
break;
}
}
}
Why is that? Why would the memory drop specifically happen during the use of that write function in one program but not the other??