如何将socket.async_read_some的读处理程序调用与特定频率同步?

时间:2015-04-15 10:30:47

标签: c++ boost client boost-asio

如何将sock.async_read_some的read_handler调用scynhronise到特定频率,同时读取812字节的流(以125 Hz频率流式传输)。

我遇到与从机器人中读取流有关的问题。我对提升asio非常新。我对这个概念知之甚少。这是我的代码中的示例块。 read_handler的作用是,它处理来自机器人的数据。该循环应该每8毫秒执行一次,这是我的采样时间,也是在它开始执行时,应该完成从机器人读取数据流。当我查看机器人的流数据时,数据每8毫秒发出一次。所以机器人数据还可以。但是read_handler的执行在某种程度上是有问题的。例如,一个循环在时间= 0开始,第二个循环在时间= 2开始,第三个循环在时间= 16开始,第四个循环在时间= 18开始,第五个循环再次从时间= 32开始。因此,触发时间循环的变化从第一次到第二次。但是在第三次它再次同步到8 ms的倍数。我需要的是read_handler应该每8毫秒触发一次(当数据到达时)但它每两次调用(总共16毫秒)就会捕获这个采样时间。这是至关重要的,因为我正在进行计算,并在稍后将命令返回给机器人(控制系统)。此代码段未详细说明发送命令等,此段仅包含非常基本的数据进程。 那么,什么可能导致调用之间的这些变化,以及如何解决它?

我搜索了网络和堆栈溢出但我无法遇到与我面临的另一个时间相关的问题。

void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{

    if (!ec)
    {
        thisLoopStart = clock();
        loopInstant[iterationNum]=diffclock(startTime, endLoopTime);
        std::cout << "Byte transfered: " << bytes_transferred << std::endl;
        printf("Byte transfered: %d", bytes_transferred);
        printf("Byte transfered: %d", bytes_transferred);
        printf("Byte transfered: %d\n", bytes_transferred);
        //std::cout << std::string(buffer.data(), bytes_transferred) << std::endl;
        char myTempDoubleTime[8];
        for (int j = 0; j<1; j++)
        {
            for (int i = 0; i < 8; i++ )
            {
                myTempDoubleTime[7-i]=buffer[4+i+8*j]; //636
            }
            memcpy(&controllerTime[iterationNum], myTempDoubleTime, 8);
        }
        endLoopTime = clock();

        thisLoopDuration = diffclock(thisLoopStart, endLoopTime);

        loopTimes[iterationNum] = thisLoopDuration;

        if (iterationNum++>500)
        {//io_service.~io_service();

            //io_service.reset();
            //io_service.run();
            exitThread = 1;
            printf("Program terminates...\n");
            GlobalObjects::myFTSystem->StopAcquisition();

            for(int i=1;i<iterationNum;i++)
                fprintf(LoopDurations, "%f\t%f\t%f\n", loopTimes[i], controllerTime[i], loopInstant[i]);


            fclose(LoopDurations);

            closeConnectionToServer();
            printf("Connection is closed...\n");
            io_service.stop();
        }
        sock.async_read_some(boost::asio::buffer(buffer), read_handler);    
    }

}

1 个答案:

答案 0 :(得分:1)

如果传入的流时间由机器人本身控制,那么你不应该担心在这样的时间特意阅读。如果您希望每隔X秒从机器人突发812个字节,只需从客户端套接字中保留async_reading即可。一旦读取完成,boost :: asio就会调用你的回调。

至于你的神秘延迟,请尝试在async_read_some调用中明确说明缓冲区的大小,如下所示:

sock.async_read_some(boost::asio::buffer(buffer, 812), read_handler);

如果你确定你总是传输足够的数据来填充这样的缓冲区,那么这应该导致你的回调被一致地调用,因为提供给boost :: asio的缓冲区已经满了。如果这不能解决您的问题,那么请按照建议执行并实现dealine_timer,您可以使用该{{3}}对异步操作进行更精细的基于时间的控制。

修改
您还应检查OnRead处理程序中的bytes_transferred,以确保您已从机器人中完整读取。现在你只是打印它。你可能有一个不完整的读取,这意味着你应该立即从套接字重复读取,直到你确定你已经消耗了你期望的所有数据。否则,你会试图对不完整的数据采取行动,最不可能在那里失败,然后启动另一个::async_read,假设你正在开始一个干净的新读取,当你真的要阅读时您忽略的旧数据并留在套接字上,并开始分段读取。

这可以解释为什么你会看到不一致的时间短于预期的时间间隔。显式指定缓冲区大小并检查您在处理程序中传递的bytes_transferred将保证您捕获此类问题。另请查看您可以传递给:: asio的completion_condition类型的文档,例如::transfer_exactly(num_bytes),但我不确定这些类型是否适用于异步读取操作。