簡體   English   中英

Boost asio async_read_until 后跟 async_read

[英]Boost asio async_read_until followed by async_read

我使用了 boost 中的異步 tcp 服務器示例,它與我的應用程序正在執行的操作很接近。 下面的代碼示例是一個完整的工作示例。

起初我開始異步讀取操作,直到分隔符字符。 在這種情況下,它是 http 標頭完整序列。 該請求包含一些有效載荷,即“hello world”(11 字節)。 對於一個簡化的例子,我在這里使用 lambda 處理程序。 第一個處理程序被調用,長度為 148,它是包括四個字節的分隔符序列的標頭。

緩沖區的大小給了我 159,這是包括有效負載在內的整個請求。 到目前為止,一切都按預期工作。 為了接收有效負載,我調用了另一個異步讀取操作,但從未調用過處理程序。 我嘗試的第一個是讀取 11 個字節,但這沒有用,所以我嘗試只讀取兩個字節來檢查它是否有效,但它不是。

streambuf 已經包含所有數據,但為什么沒有調用異步讀取處理程序。 不應該立即調用它,因為數據在緩沖區內或者是否有任何濫用 api 的情況?

編輯1:

我最終檢查了用緩沖區內的字節計算要讀取的字節。 當不需要“真正的”讀取操作時,我使用 io_server::post 為處理程序添加包裝器。 這似乎是實現此目的的最佳選擇。

#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 個字節”。

您所看到的是您不想/想要/讀取 2 個字節,因為您已經這樣做了。 你可以調整如下:

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

在一個稍微相關的說明中,似乎不會調用回調,因為您沒有顯式刷新 std::cout。 所以添加

std::cout << std::unitbuf;

in main可以消除潛在的混亂來源。

演示

住在 Coliru

這個示例在命名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";
    }
}

例如,對於“客戶”之類的

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM