gpt4 book ai didi

c++ - 由周期性 sendto()/recvfrom() 延迟引起的 UDP 套接字的周期性延迟尖峰,用于 Linux RT-PREEMPT 系统的 C++

转载 作者:太空狗 更新时间:2023-10-29 12:10:20 25 4
gpt4 key购买 nike

我设置了两个 Raspberry Pi 来使用 UDP 套接字,一个作为客户端,一个作为服务器。内核已使用 RT-PREEMPT (4.9.43-rt30+) 进行了修补。客户端充当服务器的回声,以允许计算往返延迟 (RTL)。目前在服务器端使用 10Hz 的发送频率,有 2 个线程:一个用于向客户端发送消息,一个用于从客户端接收消息。使用循环调度将线程设置为具有 95 的调度优先级。

服务器构造一条消息,其中包含发送消息的时间以及自消息开始发送以来耗时。此消息从服务器发送到客户端,然后立即返回到服务器。从客户端收到消息后,服务器会计算往返延迟,然后将其存储在 .txt 文件中,以用于使用 Python 进行绘图。

问题是,在分析图表时,我注意到 RTL 中存在周期性尖峰。图像的顶部图表:RTL latency and sendto() + recvfrom() times.在图例中我使用了 RTT 而不是 RTL。这些尖峰与服务器端 sendto() 和 recvfrom() 调用中显示的尖峰直接相关。关于如何消除这些尖峰的任何建议,因为我的应用程序非常依赖一致性?

我尝试过并注意到的事情:

  1. 发送消息的大小没有影响。我尝试了较大的消息(1024 字节)和较小的消息(0 字节)并且周期性延迟没有改变。这向我表明这不是缓冲区问题,因为没有任何内容被填满?
  2. 发送消息的频率确实起着重要作用,如果频率加倍,则延迟峰值出现的频率也会加倍。这然后表明某些东西正在填满,当它清空 sendto()/recvfrom() 函数时会遇到延迟?
  3. 使用 setsockop() 更改缓冲区大小无效。
  4. 我尝试了很多其他设置(MSG_DONTWAIT 等)都无济于事。

我绝不是套接字/C++ 编程/Linux 方面的专家,因此我将不胜感激,因为我没有想法。下面是用于创建套接字和启动服务器线程以发送和接收消息的代码。下面是从服务器发送消息的代码,如果您需要其余部分,请告诉我,但现在我的关注点集中在由 sendto() 函数引起的延迟上。如果您还需要什么,请告诉我。谢谢。

    thread_priority = priority;  
recv_buff = recv_buff_len;
std::cout << del << " Second start-up delay..." << std::endl;
sleep(del);
std::cout << "Delay complete..." << std::endl;

master = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

// master socket creation
if(master == 0){// Try to create the UDP socket
perror("Could not create the socket: ");
exit(EXIT_FAILURE);
}
std::cout << "Master Socket Created..." << std::endl;
std::cout << "Adjusting send and receive buffers..." << std::endl;
setBuff();

// Server address and port creation
serv.sin_family = AF_INET;// Address family
serv.sin_addr.s_addr = INADDR_ANY;// Server IP address, INADDR_ANY will
work on the server side only
serv.sin_port = htons(portNum);
server_len = sizeof(serv);

// Binding of master socket to specified address and port
if (bind(master, (struct sockaddr *) &serv, sizeof (serv)) < 0) {
//Attempt to bind master socket to address
perror("Could not bind socket...");
exit(EXIT_FAILURE);
}

// Show what address and port is being used
char IP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(serv.sin_addr), IP, INET_ADDRSTRLEN);// INADDR_ANY
allows all network interfaces so it will always show 0.0.0.0
std::cout << "Listening on port: " << htons(serv.sin_port) << ", and
address: " << IP << "..." << std::endl;

// Options specific to the server RPi
if(server){
std::cout << "Run Time: " << duration << " seconds." << std::endl;
client.sin_family = AF_INET;// Address family
inet_pton(AF_INET, clientIP.c_str(), &(client.sin_addr));
client.sin_port = htons(portNum);
client_len = sizeof(client);
serv_send = std::thread(&SocketServer::serverSend, this);
serv_send.detach();// The server send thread just runs continuously
serv_receive = std::thread(&SocketServer::serverReceive, this);
serv_receive.join();
}else{// Specific to client RPi
SocketServer::clientReceiveSend();
}

发送消息的代码:

    // Setup the priority of this thread
param.sched_priority = thread_priority;
int result = sched_setscheduler(getpid(), SCHED_RR, &param);
if(result){
perror ("The following error occurred while setting serverSend() priority");
}
int ched = sched_getscheduler(getpid());
printf("serverSend() priority result %i : Scheduler priority id %i \n", result, ched);

std::ofstream Out;
std::ofstream Out1;

Out.open(file_name);
Out << duration << std::endl;
Out << frequency << std::endl;
Out << thread_priority << std::endl;
Out.close();

Out1.open("Server Side Send.txt");
packets_sent = 0;

Tbegin = std::chrono::high_resolution_clock::now();

// Send messages for a specified time period at a specified frequency
while(!stop){
// Setup the message to be sent
Tstart = std::chrono::high_resolution_clock::now();
TDEL = std::chrono::duration_cast< std::chrono::duration<double>>(Tstart - Tbegin); // Total time passed before sending message
memcpy(&message[0], &Tstart, sizeof(Tstart));// Send the time the message was sent with the message
memcpy(&message[8], &TDEL, sizeof(TDEL));// Send the time that had passed since Tstart

// Send the message to the client
T1 = std::chrono::high_resolution_clock::now();
sendto(master, &message, 16, MSG_DONTWAIT, (struct sockaddr *)&client, client_len);
T2 = std::chrono::high_resolution_clock::now();
T3 = std::chrono::duration_cast< std::chrono::duration<double>>(T2-T1);
Out1 << T3.count() << std::endl;

packets_sent++;

// Pause so that the required message send frequency is met

while(true){
Tend = std::chrono::high_resolution_clock::now();
Tdel = std::chrono::duration_cast< std::chrono::duration<double>>(Tend - Tstart);
if(Tdel.count() > 1/frequency){
break;
}
}

TDEL = std::chrono::duration_cast< std::chrono::duration<double>>(Tend - Tbegin);


// Check to see if the program has run as long as required
if(TDEL.count() > duration){
stop = true;
break;
}
}

std::cout << "Exiting serverSend() thread..." << std::endl;

// Save extra results to the end of the last file
Out.open(file_name, std::ios_base::app);
Out << packets_sent << "\t\t " << packets_returned << std::endl;
Out.close();
Out1.close();
std::cout << "^C to exit..." << std::endl;

最佳答案

我已经解决了这个问题。它不是 ARP 表,因为即使禁用了 ARP 功能,也会出现周期性的峰值。在禁用 ARP 功能的情况下,只会出现一次延迟峰值,而不是一系列延迟峰值。

原来我使用的线程有问题,因为 CPU 上有两个线程,一次只能处理一个线程。发送信息的一个线程受到接收信息的第二个线程的影响。我改变了很多线程优先级(发送优先级高于接收,接收高于发送和发送等于接收)无济于事。我现在买了一个有 4 个内核的 Raspberry Pi,我将发送线程设置为在内核 2 上运行,而接收线程在内核 3 上运行,以防止线程相互干扰。这不仅消除了延迟峰值,还减少了我的设置的平均延迟。

关于c++ - 由周期性 sendto()/recvfrom() 延迟引起的 UDP 套接字的周期性延迟尖峰,用于 Linux RT-PREEMPT 系统的 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47618619/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com