当streambuf被先前的async_read填充时,boost::asio::async_read进入boost::asio::streambuf块

发布于 2024-11-15 11:55:03 字数 4054 浏览 2 评论 0原文

我搜索了其他帖子,但没有找到任何相关内容。 现在,我有一个由标头和正文组成的协议。 协议如下: 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_ 中,但我认为调用不会检查这一点?

这是输出的转储:

request_=#Z24,# n字节=24 size=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;
    }
}

I have searched other posts, but didn't found anything relevant.
Now, I have a protocol consisting of header and body.
Protocol is like:
Z24,91009802,123456789ABCDEF
Where Z24, is the header. Z is message type, 24 is remaining bytes to read. Remaining bytes is variable, so I read until first ',' is found.

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;
    }
}

Now, the header is read. But reading the footer blocks. Apparently the entire message is read in the header call. When I do the second async_read() with boost::asio::transfer_at_least(nBytes), nBytes are already in inputStreamBuffer_, but I think the call doesn't check this?

This is dump from the output:

request_=#Z24,#
nBytes=24
size=24

What is the problem, or how can I workaround it. I am a boost newbie, so all help appreciated. Thank you.

EDIT:
I tried to check the buffer fullness, and don't make async_read() call for the body if it happens to be already read by previous call.
It kind of works, but is it the right solution?

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;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我不吻晚风 2024-11-22 11:55:03

Boost ASIO 文档指出async_read_until 调用可能会将超出分隔符的数据读入缓冲区(请参阅备注部分)。话虽这么说,根据您的输入,检查缓冲区是否有更多数据的解决方案是一个很好的解决方案。

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

The Boost ASIO documentation indicates that the async_read_until call may read data into the buffer that is beyond the delimiter (see the Remarks section). That being said, your solution for checking whether the buffer has more data is a good solution given your input.

As I mentioned in my comment above, if your requirements will allow you to do so, using an integral value for the remaining bytes instead of a string is probably going to make your life easier and the code a bit cleaner and less error prone.

小ぇ时光︴ 2024-11-22 11:55:03

async_read_until 可以读取字节 超过分隔符

备注

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

async_read_until can read bytes past the delimiter

Remarks

After a successful async_read_until
operation, the streambuf may contain
additional data beyond the delimiter.
An application will typically leave
that data in the streambuf for a
subsequent async_read_until operation
to examine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文