Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 周期性sendto()/recvfrom()延迟引起UDP套接字的周期性延迟峰值,C++;用于Linux RT-PREEMPT系统_C++_Linux_Sockets_Latency_Sendto - Fatal编程技术网

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

C++ 周期性sendto()/recvfrom()延迟引起UDP套接字的周期性延迟峰值,C++;用于Linux RT-PREEMPT系统,c++,linux,sockets,latency,sendto,C++,Linux,Sockets,Latency,Sendto,我已经设置了两个Raspberry Pis来使用UDP套接字,一个作为客户端,一个作为服务器。内核已经用RT-PREEMPT(4.9.43-rt30+)进行了修补。客户端充当服务器的回显,以允许计算往返延迟(RTL)。目前,服务器端使用10Hz的发送频率,有两个线程:一个用于向客户端发送消息,另一个用于从客户端接收消息。使用循环调度将线程设置为具有95的调度优先级 服务器构造一条包含消息发送时间和自消息开始发送以来的过去时间的消息。此消息从服务器发送到客户端,然后立即返回到服务器。在从客户端接收

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

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

问题是,在分析图表时,我注意到RTL中有一个周期性尖峰。上图:在图例中,我使用了RTT而不是RTL。这些峰值与服务器端sendto()和recvfrom()调用中显示的峰值直接相关。由于我的应用程序非常依赖一致性,有没有关于如何消除这些峰值的建议

我试过并注意到的事情:

  • 正在发送的消息的大小没有影响。我尝试了较大的消息(1024字节)和较小的消息(0字节),周期延迟没有改变。这向我表明,这不是一个缓冲区问题,因为没有任何填充
  • 消息发送的频率确实起到了很大的作用,如果频率加倍,则延迟峰值出现的频率将加倍。然后,这表明有东西正在填充,当它清空sendto()/recvfrom()函数时,是否会遇到延迟
  • 使用setsockop()更改缓冲区大小无效
  • 我尝试了很多其他设置(MSG_DONTWAIT等),但都没有效果
  • 我绝对不是sockets/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();
        } 
    
    thread\u priority=优先级;
    recv_buff=recv_buff_len;
    
    我已经解决了这个问题。这不是ARP表,因为即使禁用ARP功能,也会出现周期性峰值。在禁用ARP功能的情况下,只有一个延迟峰值,而不是一系列延迟峰值


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

    作为旁注,您不应该假设
    mempy
    exit
    peror
    printf
    在全局命名空间中可用(假设
    std
    ),除非您包含了C头(你不应该这么做,因为他们不赞成)。我看到了由ARP缓存过期引起的类似情况。也就是说,每隔几分钟,目标主机的ARP条目就会过期,并且下一个UDP数据包将加倍RTT,因为ARP消息会发现IP地址。如果是这种情况,添加静态ARP条目或增加ARP超时可能会有所帮助。对于我所说的,我不是C++专家,我唯一一次遇到贬义(我认为那是正确的词)。在编译Python脚本时,控制台输出会提到任何被弃用的函数。如果我的C++脚本没有显示出任何功能,那么我就不知道这个事实了。我将接受你所说的,并根据需要更改功能。谢谢你的提示。目前我没有一个可靠的互联网连接,所以我。我无法尝试任何ARP表的更改,但一旦我能够,我会让你知道结果。你知道ARP缓存是否也会在设定数量的消息后过期吗?如果它只在设定的超时后过期,那么发送消息的频率肯定不会影响延迟峰值的位置?无论如何,我都会尽可能清空静态ARP条目。谢谢你的建议。@tambre-忘记标签了
        // 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;