【问题标题】:Long delay between a write and a read using UDP使用 UDP 的写入和读取之间的长时间延迟
【发布时间】:2020-10-01 04:28:54
【问题描述】:

我有一个运行 C++ 程序的 Raspberry Pi 4,它通过 UDP 接收和发送数据。 RPi 设置为 UDP 服务器。

UDP.hpp的代码是:

#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
};

UDP.cpp的代码是:

#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);
    }
}

然后我有一台 Windows 10 笔记本电脑,运行 Labview 程序,该程序也通过 UDP 接收和发送数据。笔记本电脑设置为 UDP 客户端。以下是 Labview 中 UDP 设置的一些示例。

图 1(打开 UDP 连接):

图 2(关闭 UDP 连接):

图 3(在 Labview 中读写 UDP):

如上,笔记本电脑上的 Labview 程序向 RPi 发送 3(“103”)+ 37(未显示)字节的数据,然后从 RPi 接收 16 字节的数据。

笔记本电脑和 RPi 通过本地网络上的 LAN 电缆连接。 RPi 使用 IP 地址 10.10.10.10 和端口 8080,笔记本电脑使用 IP 地址 10.10.10.1 和端口 1000。

以下是 Wireshark 测量,用于测量 RPi 和笔记本电脑之间不同发送和接收命令之间的时间。

图 4(wireshark 测量):

RPi 使用“Len=3”来确定在 C++ 代码中运行什么函数。 “Len=52”和“Len=37”是从笔记本电脑(Labview)发送到 RPi(C++ 代码)的数据。 “Len=16”是从 RPi 发送到笔记本电脑的数据。

笔记本电脑首先向 RPi 发送 3+52 字节的数据(客户端向服务器发送数据)。然后笔记本电脑向 RPi 发送 3+37 字节的数据(客户端向服务器发送数据)。然后 RPi 将 16 字节的数据发送回笔记本电脑(服务器将数据发送到客户端)......等等。

一个命令(3+52 字节或 3+37+16 字节)大约需要约 8 毫秒才能完成,每个命令之间的延迟约为 2 毫秒(平均)。如您所见,RPi 和笔记本电脑之间的数据大小“相对”较小(3/37/52 字节)。

现在我的问题是: 有时命令之间会有约 20 毫秒的延迟(比平均约 2 毫秒长 10 倍),我不知道为什么...(这是如图 4 中的红点所示)。这种延迟通常发生在 RPi(UDP 服务器)向笔记本电脑(UDP 客户端 - 16 字节数据)发送数据之后,但它可能发生在不同的地方,如图 4 所示(在笔记本电脑向 RPi 发送 52 字节之后)。我认为它与UDP有关,也许是设置,也许它与ARP有关,但我不知道。我尝试过超频 RPi,调整 RPi 上 C++ 程序的优先级,调整 C++ 代码,但这似乎不是瓶颈。

就像笔记本电脑和 RPi 之间的 UDP 连接有时会“丢失”或“暂停”,然后连接需要一些时间才能恢复正常。

【问题讨论】:

    标签: c++ raspberry-pi udp client-server labview


    【解决方案1】:

    我找到了解决问题的方法。为了解决长时间的延迟,我不得不降低 UDP 读取缓冲区,因为我只通过 UDP 发送小包。

    为此,我在 RPi 上格式化了 /etc 文件夹中的 sysctl.conf 文件。 我添加了以下几行:

    net.core.rmem_default = 4096

    net.core.rmem_max = 4096

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-20
      • 2016-07-31
      • 2018-06-21
      • 2017-01-08
      • 1970-01-01
      • 2021-01-20
      相关资源
      最近更新 更多