std::optional<boost::asio::ip::tcp::socket> 使用 socket.emplace() 进行初始化

std::optional<boost::asio::ip::tcp::socket> initializing using socket.emplace()

我有以下示例代码,它使用 boost::asio

实现异步服务器

我正在尝试理解代码。我对代码的疑问如下

class server中的函数async_accept()中,第一条语句是

socket.emplace(io_context)

据我了解,这一行调用套接字构造函数,创建一个套接字。 然后将此套接字传递给会话 usign std::move().

当再次调用async_accept()时,在函数的最后一行,创建了一个新的套接字。 我的理解正确吗?我错过了什么吗?

#include <iostream>
#include <optional>
#include <boost/asio.hpp>

class session : public std::enable_shared_from_this<session>
{
public:

    session(boost::asio::ip::tcp::socket&& socket)
    : socket(std::move(socket))
    {
    }

    void start()
    {
        boost::asio::async_read_until(socket, streambuf, '\n', [self = shared_from_this()] (boost::system::error_code error, std::size_t bytes_transferred)
        {
            std::cout << std::istream(&self->streambuf).rdbuf();
        });
    }

private:

    boost::asio::ip::tcp::socket socket;
    boost::asio::streambuf streambuf;
};

class server
{
public:

    server(boost::asio::io_context& io_context, std::uint16_t port)
    : io_context(io_context)
    , acceptor  (io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
    {
    }

    void async_accept()
    {
        socket.emplace(io_context);

        acceptor.async_accept(*socket, [&] (boost::system::error_code error)
        {
            std::make_shared<session>(std::move(*socket))->start();
            async_accept();
        });
    }

private:

    boost::asio::io_context& io_context;
    boost::asio::ip::tcp::acceptor acceptor;
    std::optional<boost::asio::ip::tcp::socket> socket;
};

int main()
{
    boost::asio::io_context io_context;
    server srv(io_context, 15001);
    srv.async_accept();
    io_context.run();
    return 0;
}

您对可选的理解是正确的。

 acceptor.async_accept(*socket, [&] (boost::system::error_code error)
        {
            std::make_shared<session>(std::move(*socket))->start();
            async_accept();
        });

等待连接,如果建立了连接,则执行括号内的代码,创建一个会话对象,该对象具有一个套接字作为成员,然后是“server::async_accept();”被递归调用,因此我们可以接受另一个连接。
顺便说一句:我没有看到使用可选的原因。
我建议删除成员变量

std::optional<boost::asio::ip::tcp::socket> socket;

并将 Server::async_accept() 替换为

  void
  async_accept ()
  {
    auto socket = std::make_shared<boost::asio::ip::tcp::socket> (io_context);
    acceptor.async_accept (*socket, [&, socket] (boost::system::error_code error) {
      std::make_shared<session> (std::move (*socket))->start ();
      async_accept ();
    });
  }

完整且经过测试的示例:

#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <optional>

class session : public std::enable_shared_from_this<session>
{
public:
  session (boost::asio::ip::tcp::socket &&socket) : socket (std::move (socket)) {}

  void
  start ()
  {
    boost::asio::async_read_until (socket, streambuf, '\n', [self = shared_from_this ()] (boost::system::error_code error, std::size_t bytes_transferred) { std::cout << std::istream (&self->streambuf).rdbuf (); });
  }

private:
  boost::asio::ip::tcp::socket socket;
  boost::asio::streambuf streambuf;
};

class server
{
public:
  server (boost::asio::io_context &io_context, std::uint16_t port) : io_context (io_context), acceptor (io_context, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)) {}

  void
  async_accept ()
  {
    auto socket = std::make_shared<boost::asio::ip::tcp::socket> (io_context);
    acceptor.async_accept (*socket, [&, socket] (boost::system::error_code error) {
      std::make_shared<session> (std::move (*socket))->start ();
      async_accept ();
    });
  }

private:
  boost::asio::io_context &io_context;
  boost::asio::ip::tcp::acceptor acceptor;
};

int
main ()
{
  boost::asio::io_context io_context;
  server srv (io_context, 15001);
  srv.async_accept ();
  io_context.run ();
  return 0;
}

您可以在浏览器中通过 运行 "localhost:15001" 进行测试。检查它打印的服务器输出:

GET / HTTP/1.1
Host: localhost:15001
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1

编辑:修复 liv2hak

评论中报告的错误