Периодические скачки задержки из сокета UDP, вызванные периодической задержкой sendto () / recvfrom (), C ++ для системы Linux RT-PREEMPT

Я настроил два Raspberry Pis для использования сокетов UDP, один в качестве клиента и один в качестве сервера. Ядро было исправлено с помощью RT-PREEMPT (4.9.43-rt30 +). Клиент действует как эхо-сигнал к серверу, что позволяет рассчитывать задержку прохождения сигнала туда и обратно (RTL). В настоящее время на стороне сервера используется частота отправки 10 Гц с двумя потоками: один для отправки сообщений клиенту и один для приема сообщений от клиента. Потоки настроены на приоритет расписания 95 с использованием кругового планирования.

Сервер создает сообщение, содержащее время, когда оно было отправлено, и время, прошедшее с момента начала отправки сообщений. Это сообщение отправляется с сервера клиенту, а затем немедленно возвращается на сервер. Получив сообщение от клиента, сервер рассчитывает задержку прохождения сигнала в обоих направлениях и затем сохраняет его в файле .txt, который будет использоваться для построения графиков с использованием Python.

Проблема в том, что при анализе графиков я заметил, что в RTL наблюдается периодический всплеск. Верхний график изображения:Задержка RTL и sendto () + recvfrom () раз. В легенде я использовал 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;

2

Решение

Я разобрался с проблемой. Это были не таблицы ARP, поскольку даже при отключенной функции ARP периодически возникал всплеск. Если функция ARP отключена, задержка будет только одна, в отличие от серии задержек.

Это оказалось проблемой с потоками, которые я использовал, поскольку в ЦП было два потока, способных обрабатывать только один поток за раз. Один поток, который отправлял информацию, был затронут вторым потоком, который получал информацию. Я много изменил приоритеты потоков (приоритет отправки выше, чем получение, получение выше, чем отправка и отправка равна получению) безрезультатно. Я купил Raspberry Pi с четырьмя ядрами и настроил поток отправки на ядро ​​2, в то время как поток приема работает на ядре 3, предотвращая взаимодействие потоков друг с другом. Это не только сняло пики задержки, но и уменьшило среднюю задержку моей установки.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]