read_some() 工作但很慢,read() 不

read_some() works but very slow, read() doesn't

本文关键字:read 工作 some      更新时间:2023-10-16

下面的代码肯定有效,但没有我预期的那么快。

我希望我的程序以非常好的速度读取数据。还有另一个商业应用程序可以连接到同一服务器并以惊人的速度恢复数据。服务器端不是问题。

class A
{
    //...
    boost::asio::ip::tcp::socket* myPort;
}
void A::OpenPort()
{
    if(myPort)
    {
        if(myPort->is_open())
        {
            return;
        }
    }
    // make the connection
    Connect();
    if(! myPort->is_open())
    {
        return;
    }
    // set the protocol
    static string init("INITrn");
    myPort->write_some(boost::asio::buffer(init.c_str(), init.length()));
}   
void A::Read()
{
    static string prev_msg = "";
    try
    {
        OpenPort();
        while(true)
        {                   
            boost::system::error_code error;
                boost::asio::streambuf streamBuf;
                boost::asio::streambuf::mutable_buffers_type mutableBuffer = streamBuf.prepare(614400);
                size_t bytes_transferred = myPort->read_some(boost::asio::buffer(mutableBuffer), error);
                if (error)
                {
                    if (error != boost::asio::error::eof)
                    {
                        throw boost::system::system_error(error); // Some other error.
                    }
                }
                // add to any previous message we might not have processed
                streamBuf.commit(bytes_transferred);
                istreambuf_iterator<char> sbit(&streamBuf);
                istreambuf_iterator<char> end;
                string s(sbit, end);
                prev_msg.append(s);
                string delimiter1 = ",rn";
                size_t pos1 = 0;
                string response;
                while ((pos1 = prev_msg.find(delimiter1)) != std::string::npos)
                {
                    response = prev_msg.substr(0, pos1);
                    //SOME PROCESSING ON THE RESPONSE RECEIVED
                }
        }
    }
    catch (boost::system::system_error const& ex)
    {
        cout<<ex.what();
    }
}

显然,问题出在read_some(),程序在一次读取操作中没有读取完整的数据,有时它接收614000字节,有时接收到非常少。我不想对缓冲区的大小施加任何限制,无论服务器发送什么,程序都应该一次性读取所有数据。

因此,我决定只使用 read()。但是,现在程序卡在 read();read() 调用不返回。

boost::asio::streambuf streamBuf;
size_t bytes_transferred = read(*myPort, streamBuf, error);
if (error)
{
    if (error != boost::asio::error::eof)
    {
        throw boost::system::system_error(error); // Some other error.
    }
}

在请求下一个数据之前,我必须处理收到的数据,因此我不能使用 async_read()。

不要在每个循环上分配新的缓冲区,只在循环外分配一次。

    while(true)
    {                   
        boost::system::error_code error;
            boost::asio::streambuf streamBuf;
            boost::asio::streambuf::mutable_buffers_type mutableBuffer = streamBuf.prepare(614400);
            size_t bytes_transferred = myPort->read_some(boost::asio::buffer(mutableBuffer), error);
...

替换为

    boost::system::error_code error;
    boost::asio::streambuf streamBuf;
    boost::asio::streambuf::mutable_buffers_type mutableBuffer = streamBuf.prepare(614400);
    while(true)
    {                   
            size_t bytes_transferred = myPort->read_some(boost::asio::buffer(mutableBuffer), error);
...

几件事:

  • 使用TCP,您永远无法确定您将一次性收到所有内容。
  • 因为您正在阅读分隔符,所以read_until()可能是您所追求的。
  • 确保用O_NDELAY打开套接字,否则写入时间将增加 200 毫秒。为此,请在代码中适当的情况下调用myPort->set_option(tcp::no_delay(true))
  • 睡眠不是一个好主意。设计代码,使其没有必要。
  • 如果套接字关闭,您的代码似乎进入无限循环。
  • 在不检查返回值的情况下调用write_some()。您可能应该调用write()以确保写入所有数据。
  • 如果你有很多线程,你可能会从重新设计你的代码来获得改进,成为异步的。