Sending packets with TCP sockets continuously

I am working on a project where I read sensor data on a NUCLEO-L432KC and send it to a NUCLEO-F767ZI using TCP sockets in Mbed 6.15. The only way I can get it to work is to close the socket and reopen after each packet. When I am sending the packet to a YAT terminal on my PC it works to leave the socket open and is much faster.
The client device code is

#include “mbed.h”

#include “ICM20948.h”

#include “ESP8266Interface.h”

using namespace std::chrono;

ESP8266Interface wifi(PA_9, PA_10); //(TX, RX)

ICM20948 imu(PB_4, PA_7); //(SDA, SCL)

Timer t;

// Static IP network variables

static const char* mbedIP = “192.168.1.253”; //IP setting with ESP8266 not supported

static const char* mbedMask = “255.255.255.0”; // Mask

static const char* mbedGateway = “192.168.1.254”; //Gateway

static const char* recvIP = “192.168.1.38”; //my other mbed

//static const char* recvIP = “192.168.1.212”; //my laptop

const int PORT = 80; //Port used for UDP communication

int main()

{

DigitalOut led(LED1);

int code;

//wifi stuff

//code = wifi.set_network(mbedIP, mbedMask, mbedGateway);

//printf("IP set %d\r\n", code);

printf("TCP Socket example\n");

//SocketAddress sockAddr(recvIP, NSAPI_IPv4, PORT); // wrong

SocketAddress sockAddr;

SocketAddress remoteSockAddr(recvIP, PORT);

printf("Running\n");

wifi.connect("*myrouter*", "*mypassword*", NSAPI_SECURITY_WPA2);

printf("%d\r\n", code);

wifi.get_ip_address(&sockAddr);

printf("IP address is: %s\n", sockAddr.get_ip_address() ? sockAddr.get_ip_address() : "No IP");

//IMU stuff

printf("hello IMU!\r\n");

led = 1;

code = imu.whoAmI();

printf("%d \r\n", code);

led = !led;

imu.init();

led = !led;

printf("IMU initialized\r\n");

//socket stuff

TCPSocket td_sock;

td_sock.open(&wifi);

td_sock.connect(remoteSockAddr);

int send_counter = 0;

t.start();

while (true) {

    //led = !led;

    float ax, ay, az, gx, gy, gz;

    float ax_data[10], ay_data[10], az_data[10];

    float ax_delta[10], ay_delta[10], az_delta[10];

    unsigned int time = duration_cast<microseconds>(t.elapsed_time()).count();

    unsigned int time_tot = time + time_tot;

    //printf("%d\r\n", time);

    t.reset();

    imu.getAccGyro(&ax, &ay, &az, &gx, &gy, &gz);

    //shift data down a position

    for (int i = 9; i > 0; i--) {

        ax_data[i] = ax_data[i-1];

        ay_data[i] = ay_data[i-1];

        az_data[i] = az_data[i-1];

    }

    //add new first position

    ax_data[0] = ax;

    ay_data[0] = ay;

    az_data[0] = az;

    //find diffence in all previous stored time stamps and integrate over communication window

    for (int i = 1; i < 10; i++){

        ax_delta[i-1] = ax_delta[i-1] + abs(ax - ax_data[i]);

        ay_delta[i-1] = ay_delta[i-1] + abs(ay - ay_data[i]);

        az_delta[i-1] = az_delta[i-1] + abs(az - az_data[i]);

    }

    send_counter ++;

    if (send_counter > 99){

        char  out_buffer[64];

        out_buffer[0] = (time_tot >> 24);

        out_buffer[1] = ((time_tot >> 16) & 0xFF);

        out_buffer[2] = ((time_tot >> 8) & 0xFF);

        out_buffer[3] = (time_tot & 0xFF);

        for (int i = 0; i < 10; i++){

            unsigned int _ax_delta[10], _ay_delta[10], _az_delta[10];

            _ax_delta[i] = static_cast<int>(ax_delta[i] * 100.0f);

            _ay_delta[i] = static_cast<int>(ay_delta[i] * 100.0f);

            _az_delta[i] = static_cast<int>(ay_delta[i] * 100.0f);

            ax_delta[i] = 0;

            ay_delta[i] = 0;

            az_delta[i] = 0;

            out_buffer[(i*6) + 4] = (_ax_delta[i] >> 8);

            out_buffer[(i*6) + 5] = (_ax_delta[i] & 0xFF);

            out_buffer[(i*6) + 6] = (_ay_delta[i] >> 8);

            out_buffer[(i*6) + 7] = (_ay_delta[i] & 0xFF);

            out_buffer[(i*6) + 8] = (_az_delta[i] >> 8);

            out_buffer[(i*6) + 9] = (_az_delta[i] & 0xFF);

        }

        code = td_sock.sendto(remoteSockAddr, out_buffer, sizeof(out_buffer));

        td_sock.close();

        td_sock.open(&wifi);

        td_sock.connect(remoteSockAddr);

        printf("%d \r\n", code);

        led = !led;

        time_tot = 0;

        send_counter = 0;

    }

}

}

The server device code is

#include “mbed.h”

#include “EthernetInterface.h”

DigitalOut led1(LED1);

DigitalOut led2(LED2);

#define IP “192.168.1.38”

#define GATEWAY “192.168.1.254”

#define NETMASK “255.255.255.0”

#define PORT 80

EthernetInterface* net;

TCPSocket server;

TCPSocket* clientSocket;

SocketAddress clientAddress;

char rxBuf[64];

int main(void)

{

printf("Starting\r\n");

net = new EthernetInterface;

net->set_network(IP, NETMASK, GATEWAY);

if (!net) {

    printf("Error! No network inteface found.\n");

    return 0;

}

//net->set_network (IP, NETMASK, GATEWAY);  // include to use static IP address

nsapi_size_or_error_t   r = net->connect();

if (r != 0) {

    printf("Error! net->connect() returned: %d\n", r);

    return r;

}

// Show the network address

SocketAddress   ip;

SocketAddress   netmask;

SocketAddress   gateway;

net->get_ip_address(&ip);

net->get_netmask(&netmask);

net->get_gateway(&gateway);

ip.set_port(PORT);

const char*     ipAddr = ip.get_ip_address();

const char*     netmaskAddr = netmask.get_ip_address();

const char*     gatewayAddr = gateway.get_ip_address();

printf("IP address: %s\r\n", ipAddr ? ipAddr : "None");

printf("Netmask: %s\r\n", netmaskAddr ? netmaskAddr : "None");

printf("Gateway: %s\r\n\r\n", gatewayAddr ? gatewayAddr : "None");

while (true) {

    printf("===================\r\n");

    nsapi_error_t   error = 0;

    server.open(net);

    server.bind(ip);

    server.listen(5);

    clientSocket = server.accept(&error);

    if (error != 0) {

        printf("Connection failed!\r\n");

    }

    else {

        //clientSocket->set_timeout(200);

        clientSocket->getpeername(&clientAddress);

        printf("Client with IP address %s connected.\r\n\r\n", clientAddress.get_ip_address());

        error = clientSocket->recv(rxBuf, sizeof(rxBuf));

        printf("%d, %d, %d, %d\r\n", rxBuf[0], rxBuf[1],  rxBuf[2], rxBuf[3]);

    }

    clientSocket->close();

}

}

Is there a better way to do this and does anyone have advice about the best next step to add more than one client device running at the same time?

Hello,

I do not tell you why it happens for now but for your next step requirements (multi client) you need to open/close socket anyway. It is not possible to do this without it. You can do it only when P2P. The server can to serve only one client connected at time, the rest are pending in queue until the current one is not disconnected.

BR, Jan

Ok, I started with the example in this thread HTTP-Server based on TCPSocket (mbed os 6!)
and was unsure what the comment meant or what the number did.

/* Can handle 5 simultaneous connections */
server.listen(5);

To do the multiple clients do I need to make a new port for each client?

From my point of view, that sentence is probably not exact. Documentation says “Number of pending connections that can be queued simultaneously, defaults to 1.”. And also how you can see in the example what did you mentioned, it is handled with open/close of socket.
Anyway there are default limits of sockets what can be handled, and can be set/override by via mbed_app.json - source.

For example (max should be your max +1, I think)

{
    "target_overrides": {
        "*": {
            "lwip.socket-max": 8,
            "lwip.tcp-socket-max": 7,
        }
    }
}

BR, Jan

Thank you for the help. Unfortunately this is pretty slow and is difficult to manage having multiple clients. I figured out that I can have multiple Mbed devices send to the same port on a Linux machine at the same time without closing the socket so I think that will be what I do on this project. The code on the mbed device ends up being.

#include “mbed.h”
#include “EthernetInterface.h”

DigitalOut led1(LED1);

// Static IP network variables
static const char* mbedIP = “192.168.1.45”; //IP
static const char* mbedMask = “255.255.255.0”; // Mask
static const char* mbedGateway = “192.168.1.254”; //Gateway
static const char* recvIP = “192.168.1.230”; //my raspberry pi
//static const char* recvIP = “192.168.1.212”; //my laptop
const int PORT = 80; //Port used for UDP communication
EthernetInterface eth; //Ethernet interface
int main()
{
//eth.set_network(mbedIP, mbedMask, mbedGateway);
printf(“TCP Socket example\n”);
SocketAddress sockAddr;
SocketAddress remoteSockAddr(recvIP, PORT);
if (eth.connect() != 0) {
printf(“Unable to connect to the Ethernet.\r\n”);
return -1;
}
eth.get_ip_address(&sockAddr);
printf(“IP address is: %s\n”, sockAddr.get_ip_address() ? sockAddr.get_ip_address() : “No IP”);
TCPSocket td_sock;
td_sock.open(&eth);
char out_buffer = " very important data";
while (true) {
int code = td_sock.sendto(remoteSockAddr, out_buffer, sizeof(out_buffer));
int i, err_count;
if (i > 9) i = 0;
out_buffer[0] = i;
if (code < 0) {
err_count ++;
if (err_count > 2) {
td_sock.close();
td_sock.open(&eth);
td_sock.connect(remoteSockAddr);
}
}
else err_count = 0;
//int code = td_sock.send(out_buffer, sizeof(out_buffer));
printf(“%d \r\n”, code);
led1 = !led1;
i++;
ThisThread::sleep_for(200ms);
}
}

Because if the Linux program restarts it has to reconnect but otherwise it stays open.

I don’t understand this behavior, in the moment I try to program an Arduino Opta with the same problem. I have had this problem also with mbed on a Nucleo board some years ago. Start and stopping the socket cause many problems on the connected applications including losing the send packet. What a bullshit. Mbed is dead for me.

this sequence in a loop is not correct. Once the listen() has started, you can wait in a loop for getting client accepts().

Then it maybe also an issue that a socket is not reusable immediately. This is a recommended behavior from the Berkley sockets, not a Mbed invention. There is a socket option to change this and a socket can be opened again without waiting if it is set.