提升asio async_read_until,然后是async_read [英] Boost asio async_read_until followed by async_read

查看:132
本文介绍了提升asio async_read_until,然后是async_read的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了来自boost的异步tcp服务器示例,该示例接近我的应用程序正在执行的操作.下面的代码示例是一个完整的示例.

I used the async tcp server example from boost which is near to what my application is doing. The code example below is a fully working example.

首先,我开始异步读取操作,直到定界符char.在这种情况下,它是http标头完成序列.该请求包含一些有效负载,即"hello world"(11个字节).对于一个简化的示例,我在这里使用lambda处理程序.第一个处理程序称为长度148,它是标头,包括定界符序列的四个字节.

At first I start an async read operation until the delimiter char. In this case it is the http header complete sequence. The request contains some payload which is "hello world" (11 bytes). For a simplified example I use lambda handlers here. The first handler is called wit a length of 148 which is the header including four bytes for the delimiter sequence.

缓冲区的大小为159,这是包括有效负载在内的整个请求.到目前为止,一切都按预期进行.为了接收有效载荷,我调用了另一个异步读取操作,但从未调用处理程序.我尝试的第一个尝试是读取11个字节,但是它不起作用,因此我尝试仅读取两个字节以检查它是否有效,但事实并非如此.

The size of the buffer gives me 159 which is the whole request including the payload. So far everything works as expected. To receive the payload I call another async read operation but the handler is never called. The first I tried was to read 11 bytes but that didn't work so I tried to read just two bytes to check if it's working buts it isn't.

streambuf已经包含所有数据,但是为什么未调用异步读取处理程序.不应该立即调用它,因为数据在缓冲区内还是对api有任何滥用?

The streambuf already contains all the data but why is the async read handler not called. Shouldn't it be called immediately because the data is inside the buffer or is there any misuse of the api?

我最终检查了要读取的字节与缓冲区内的字节.当不需要"true"读取操作时,我使用io_server :: post为处理程序添加一个包装器.为此,这似乎是最佳选择.

I ended up checking calculating the bytes to read with the bytes inside the buffer. When there is no need for a "true" read operation I use io_server::post to add a wrapper for the handler. This seems as the best option for that purpose.

#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class session
  : public std::enable_shared_from_this<session>
{
public:
  session(tcp::socket socket)
    : socket_(std::move(socket))
  {
  }

    boost::asio::streambuf buf;

  void start()
  {
    do_read();
  }

private:
  void do_read()
  {
    auto self(shared_from_this());

    boost::asio::async_read_until(socket_,buf, "\r\n\r\n", [this, self](boost::system::error_code ec, std::size_t length){
        std::istream in(&buf);
        std::cout << length << std::endl;
        std::cout << buf.size() << std::endl;
        in.ignore(length);
        boost::asio::async_read(socket_, buf, boost::asio::transfer_exactly(2), [this, self](boost::system::error_code ec, std::size_t length){
            std::istream in(&buf);
            std::cout << length << std::endl;
        });
    });
  }

  void do_write(std::size_t length)
  {
    auto self(shared_from_this());
    boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }

  tcp::socket socket_;
  enum { max_length = 1024 };
  char data_[max_length];
};

class server
{
public:
  server(boost::asio::io_service& io_service, short port)
    : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
      socket_(io_service)
  {
    do_accept();
  }

private:
  void do_accept()
  {
    acceptor_.async_accept(socket_,
        [this](boost::system::error_code ec)
        {
          if (!ec)
          {
            std::make_shared<session>(std::move(socket_))->start();
          }

          do_accept();
        });
  }

  tcp::acceptor acceptor_;
  tcp::socket socket_;
};

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: async_tcp_echo_server <port>\n";
      return 1;
    }

    boost::asio::io_service io_service;

    server s(io_service, std::atoi(argv[1]));

    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

推荐答案

第二个 async_read 仅读取2个字节.您明确表示要精确传输2个字节".

The second async_read just reads 2 bytes. You explicitly say you want to "transfer exactly 2 bytes".

您正在查看的是您不希望读取2个字节,因为您已经读过.您可以像这样调整:

What you're looking at is that you do not /want/ to read 2 bytes, because you already did. You could adjust like:

size_t to_transfer = 2 - std::min(2ul, buf.size());
boost::asio::async_read(socket_, buf, boost::asio::transfer_exactly(to_transfer),

在一个稍微相关的注释上,它可能似乎不被调用,因为您没有显式刷新std :: cout.因此,添加

On a slightly related note, it can seem for the callback to not be invoked because you donot explicit flush std::cout. So adding

std::cout << std::unitbuf;

main 中的

可以消除潜在的混乱来源.

in main can remove that potential source of confusion.

在Coliru上直播

此示例在命名 length (不是长度,它是 bytes_transferred )并为 buf.size()转储更多值时更加谨慎所以您会看到真正发生了什么.

This sample is more careful in naming length (it's not length, it's bytes_transferred) and dumping more values for buf.size() so you'll see what is really happening.

#include <boost/asio.hpp>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>

using boost::asio::ip::tcp;

class session : public std::enable_shared_from_this<session> {
  public:
    session(tcp::socket&& s) : socket_(std::move(s)) {}

    boost::asio::streambuf buf;

    void start() { do_read(); }

  private:
    void do_read() {
        auto self(shared_from_this());

        boost::asio::async_read_until(
            socket_, buf, "\r\n\r\n", [this, self](boost::system::error_code ec, std::size_t transferred) {
                std::cout << "async_read_until -> " << ec.message() << "\n";
                {
                    std::cout << "transferred: " << transferred << std::endl;
                    std::cout << "buffer: " << buf.size() << std::endl;
                    {
                        std::istream in(&buf);
                        in.ignore(transferred);
                    }
                    std::cout << "remaining buffer: " << buf.size() << std::endl;
                }

                size_t to_transfer = 2 - std::min(2ul, buf.size());
                boost::asio::async_read(socket_, buf, boost::asio::transfer_exactly(to_transfer),
                    [this, self](boost::system::error_code ec, std::size_t transferred) {
                        std::cout << "async_read -> " << ec.message() << "\n";
                        std::cout << "transferred: " << transferred << std::endl;
                        std::cout << "buffer: " << buf.size() << std::endl;
                        {
                            std::istream in(&buf);
                            char a, b;
                            if (in >> a >> b) {
                                std::cout << "Payload: '" << a << b << "'\n";
                            }
                        }
                        std::cout << "remaining buffer: " << buf.size() << std::endl;
                    });
            });
    }

    friend class server;
    tcp::socket socket_;
};

class server {
  public:
    server(boost::asio::io_service &io_service, short port) : acceptor_(io_service, tcp::endpoint({}, port)), socket_(io_service) {
        do_accept();
    }

  private:
    void do_accept() {
        acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
            std::cout << "async_accept -> " << ec.message() << "\n";
            if (!ec) {
                std::make_shared<session>(std::move(socket_))->start();
                //do_accept();
            }
        });
    }

    tcp::acceptor acceptor_;
    tcp::socket socket_;
};

int main() {
    std::cout << std::unitbuf;
    try {
        boost::asio::io_service io_service;

        server s(io_service, 6767);

        io_service.run();
    } catch (std::exception &e) {
        std::cerr << "Exception: " << e.what() << "\n";
    }
}

例如带有客户"之类的

echo -e 'hello\r\n\r\nmore to come' | netcat localhost 6767

输出看起来像

async_accept -> Success
async_read_until -> Success
transferred: 9
buffer: 22
remaining buffer: 13
async_read -> Success
transferred: 0
buffer: 13
Payload: 'mo'
remaining buffer: 11

这篇关于提升asio async_read_until,然后是async_read的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆