简体   繁体   English

Boost asio async_read_until 后跟 async_read

[英]Boost asio async_read_until followed by async_read

I used the async tcp server example from boost which is near to what my application is doing.我使用了 boost 中的异步 tcp 服务器示例,它与我的应用程序正在执行的操作很接近。 The code example below is a fully working example.下面的代码示例是一个完整的工作示例。

At first I start an async read operation until the delimiter char.起初我开始异步读取操作,直到分隔符字符。 In this case it is the http header complete sequence.在这种情况下,它是 http 标头完整序列。 The request contains some payload which is "hello world" (11 bytes).该请求包含一些有效载荷,即“hello world”(11 字节)。 For a simplified example I use lambda handlers here.对于一个简化的例子,我在这里使用 lambda 处理程序。 The first handler is called wit a length of 148 which is the header including four bytes for the delimiter sequence.第一个处理程序被调用,长度为 148,它是包括四个字节的分隔符序列的标头。

The size of the buffer gives me 159 which is the whole request including the payload.缓冲区的大小给了我 159,这是包括有效负载在内的整个请求。 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.我尝试的第一个是读取 11 个字节,但这没有用,所以我尝试只读取两个字节来检查它是否有效,但它不是。

The streambuf already contains all the data but why is the async read handler not called. streambuf 已经包含所有数据,但为什么没有调用异步读取处理程序。 Shouldn't it be called immediately because the data is inside the buffer or is there any misuse of the api?不应该立即调用它,因为数据在缓冲区内或者是否有任何滥用 api 的情况?

Edit1:编辑1:

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.当不需要“真正的”读取操作时,我使用 io_server::post 为处理程序添加包装器。 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;
}

The second async_read just reads 2 bytes.第二个async_read只读取 2 个字节。 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.您所看到的是您不想/想要/读取 2 个字节,因为您已经这样做了。 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),

On a slightly related note, it can seem for the callback to not be invoked because you donot explicit flush std::cout.在一个稍微相关的说明中,似乎不会调用回调,因为您没有显式刷新 std::cout。 So adding所以添加

std::cout << std::unitbuf;

in main can remove that potential source of confusion. in main可以消除潜在的混乱来源。

DEMO演示

Live On Coliru 住在 Coliru

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.这个示例在命名length (它不是长度,它是bytes_transferred )和为buf.size()转储更多值时更加小心,所以你会看到真正发生了什么。

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

For example with a "client" like例如,对于“客户”之类的

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

The output looks like输出看起来像

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM