I have a Raspberry Pi 4 running a C++ program where it receives and sends data via UDP. The RPi is setup as a UDP server.
The code for UDP.hpp is:
#pragma once
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string>
using namespace std;
/////GLOBAL CONSTANTS/////
const int c_PORT = 8080;
class UDP
{
private:
int fdSocketUDP_; //File descriptor for UDP socket
int ClientAddressLength_; //Length of client address
struct sockaddr_in ServerAddress_; //Struct handling internet address for server
struct sockaddr_in ClientAddress_; //Struct handling internet address for client
public:
UDP(); //Initialize and bind socket
~UDP(); //Close socket
string readUDP(const int readSize); //Read via UDP protocol
void writeUDP(string message); //Write via UDP protocol
};
The code for UDP.cpp is:
#include "udp.hpp"
UDP::UDP()
{
if ((fdSocketUDP_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) //Create UDP socket
{
perror("Error - socket creation - udp.cpp");
exit(EXIT_FAILURE);
}
memset(&ServerAddress_, 0, sizeof(ServerAddress_)); //Sets ServerAddress_ to 0
memset(&ClientAddress_, 0, sizeof(ClientAddress_)); //Sets ClientAddress_ to 0
ServerAddress_.sin_family = AF_INET; //Address family, must be AF_INET = IPv4
ServerAddress_.sin_port = htons(c_PORT); //PORT number, convert PORT number to network byte order using htons()
ServerAddress_.sin_addr.s_addr = INADDR_ANY; //IP-Address of host (server IP), INADDR_ANY gets this IP Address
if (bind(fdSocketUDP_, (const struct sockaddr *)&ServerAddress_, sizeof(ServerAddress_)) < 0) //Bind the socket to ServerAddress_
{
perror("Error - socket bind - udp.cpp");
exit(EXIT_FAILURE);
}
}
UDP::~UDP()
{
close(fdSocketUDP_); //Close socket
}
string UDP::readUDP(const int readSize)
{
char readMsg[readSize] = {0}; //Read buffer
ClientAddressLength_ = sizeof(ClientAddress_);
if ((recvfrom(fdSocketUDP_, readMsg, readSize, 0, (struct sockaddr *)&ClientAddress_, (socklen_t *)&ClientAddressLength_)) < 0) //Receive data via UDP protocol
{
perror("Error - recvfrom - udp.cpp");
exit(EXIT_FAILURE);
}
string str(readMsg); //Convert char array to string
str = str.substr(0, readSize); //Make sure the string is the length of readsize
return str;
}
void UDP::writeUDP(string message)
{
//Make char array
int writeSize = message.size();
char writeMsg[writeSize + 1] = {'\0'};
//Convert string message to char array
for (int i = 0; i < writeSize; i++)
{
writeMsg[i] = message[i];
}
if ((sendto(fdSocketUDP_, writeMsg, writeSize, 0, (const struct sockaddr *)&ClientAddress_, (socklen_t)ClientAddressLength_)) < 0) //Send data via UDP protocol
{
perror("Error - sendto - udp.cpp");
exit(EXIT_FAILURE);
}
}
I then have a windows 10 laptop, running a Labview program that also receives and sends data via UDP. The laptop is setup as a UDP client. Below are som examples of the UDP setup in Labview.
Image 1 (Open UDP connection):
Image 2 (Close UDP connection):
Image 3 (Write and read UDP in Labview):
Above, the Labview program on the laptop sends 3 ("103") + 37 (not shown) bytes of data to the RPi, and then receives 16 bytes of data from the RPi.
The laptop and RPi are connected via a LAN-cable on a local network. The RPi uses IP-address 10.10.10.10 and port 8080, and the laptop uses IP-address 10.10.10.1 and port 1000.
Below are a Wireshark measurement, that measures the time between the different send and receive commands between the RPi and laptop.
Image 4 (wireshark measurement):
The "Len=3" is used by the RPi to determine what function to run in the C++ code. The "Len=52" and "Len=37" is data sent from the laptop (Labview) to the RPi (C++ code). The "Len=16" is data sent from the RPi to the laptop.
The laptop first sends 3+52 bytes of data to the RPi (client sends data to server). The laptop then sends 3+37 bytes of data to the RPi (client sends data to server). The RPi then sends 16 bytes of data back to the laptop (server sends data to client)... and so on.
One command (3+52 bytes or 3+37+16 bytes) takes about ~8ms to finish, with ~2ms latency (on average) between each command. As you can see, the data sizes between the RPi and laptop are "relatively" small (3/37/52 bytes).
Now my problem: Sometimes there is a delay of ~20ms between the commands (10 times longer than the average of ~2ms), and I don't know why... (this is shown with the red dots on image 4). This delay often comes after the RPi (UDP server) sends data to the laptop (UDP client - the 16 bytes of data), but it can happen at different places, as shown on image 4 (after the laptop sends 52 bytes to the RPi). I think it has something to do with the UDP, maybe the setup, maybe it has something to do with ARP, but I don't know. I have tried overclocking the RPi, tweaking the priority of the C++ program on the RPi, tweaking the C++ code, but that doesn't seem to be the bottleneck.
It's like the UDP connection between the laptop and RPi is "lost" or "paused" sometimes and it then takes some time for the connection to come back on track.
I found a solution to my problem. To solve the long delay, i had to lower the UDP read buffer, since i'm only sending small packages via UDP.
To do this, i formatted the sysctl.conf file on the RPi, located in the /etc folder. I added the lines:
net.core.rmem_default = 4096
net.core.rmem_max = 4096