当前一个async_read填充streambuf时,boost :: asio :: async_read进入boost :: asio :: streambuf块

时间:2011-06-16 11:10:43

标签: c++ boost boost-asio

我搜索了其他帖子,但没有发现任何相关内容。 现在,我有一个由标题和正文组成的协议。 协议如下: Z24,91009802,123456789ABCDEF 其中Z24是标题。 Z是消息类型,24是要读取的剩余字节。剩下的字节是可变的,所以我读到第一个','才找到。

void handle_handshake(const boost::system::error_code& error)
{
    if (!error)
    {
        boost::asio::async_read_until(
            socket_,
            inputStreamBuffer_,
            ',',
            boost::bind(
                &session::doReadHeader, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred)
        );
    }
    else
    {
        delete this;
    }
}

void doReadHeader(
    const boost::system::error_code& error,
    size_t bytes_transferred)
{
    if (!error)
    {
        istream is(&inputStreamBuffer_);
        vector<char> v(bytes_transferred);
        is.read(&(v[0]),bytes_transferred);
        request_.append(v.begin(),v.end());

        cout << "request_=#" << request_ << "#" << endl;
        int nBytes=string_to_llint(request_.substr(1,request_.size()-2));
        cout << "nBytes=" << nBytes << endl;
        cout << "size=" << inputStreamBuffer_.size() << endl;

        boost::asio::async_read(
            socket_,
            inputStreamBuffer_,
            boost::asio::transfer_at_least(nBytes),
            boost::bind(
                &session::doReadBody, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred)
        );
    }
    else
    {
        delete this;
    }
}

void doReadBody(
    const boost::system::error_code& error,
    size_t bytes_transferred)
{
    if (!error)
    {
        istream is(&inputStreamBuffer_);
        vector<char> v(bytes_transferred);
        is.read(&(v[0]),bytes_transferred);
        request_.append(v.begin(),v.end());

        string response=cardIssueProcessor_.process(request_);
        cout << "request=#" << request_ << "#" << endl;
        cout << "response=#" << response << "#" << endl;
        request_.clear();

        boost::asio::async_write(
            socket_,
            boost::asio::buffer(response, response.size()),
            boost::bind(
                &session::doWriteResponse, this,
                boost::asio::placeholders::error)
        );
    }
    else
    {
        delete this;
    }
}

现在,读取标题。但阅读页脚块。显然,在标题调用中读取整个消息。当我使用boost :: asio :: transfer_at_least(nBytes)执行第二个async_read()时,nBytes已经在inputStreamBuffer_中,但我认为调用不会检查这个吗?

这是输出中的转储:

请求_ =#Z24,# 为nbytes = 24 大小= 24

问题是什么,或者我该如何解决它?我是一个助推新手,所以所有的帮助表示赞赏。谢谢。

编辑: 我试图检查缓冲区的完整性,如果它恰好已被前一次调用读取,则不要对正文进行async_read()调用。 它有点有效,但它是正确的解决方案吗?

void doReadHeader(
    const boost::system::error_code& error,
    size_t bytes_transferred)
{
    if (!error)
    {
        istream is(&inputStreamBuffer_);
        vector<char> v(bytes_transferred);
        is.read(&(v[0]),bytes_transferred);
        request_.assign(v.begin(),v.end());

        cout << "request_=#" << request_ << "#" << endl;
        int nBytes=string_to_llint(request_.substr(1,request_.size()-2));
        cout << "nBytes=" << nBytes << endl;
        cout << "size=" << inputStreamBuffer_.size() << endl;

        size_t toReadBytes=nBytes-inputStreamBuffer_.size();
        if (toReadBytes>0)
        {
            boost::asio::async_read(
                socket_,
                inputStreamBuffer_,
                boost::asio::transfer_at_least(toReadBytes),
                boost::bind(
                    &session::doReadBody, this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred)
            );
        }
        else
        {
            doReadBody(error,nBytes);
        }
    }
    else
    {
        delete this;
    }
}

2 个答案:

答案 0 :(得分:2)

The Boost ASIO documentation表示async_read_until调用可能会将数据读入超出分隔符的缓冲区(请参阅“备注”部分)。话虽如此,根据您的输入,您检查缓冲区是否有更多数据的解决方案是一个很好的解决方案。

正如我在上面的评论中提到的,如果您的要求允许您这样做,那么使用剩余字节的整数值而不是字符串可能会让您的生活更轻松,代码更清晰,错误更少易发生。

答案 1 :(得分:1)

async_read_until可以读取字节past the delimiter

  

说明

     

成功的async_read_until之后   操作,streambuf可能包含   超出分隔符的其他数据。   申请通常会离开   在streambuf中的数据   后续的async_read_until操作   检查。