为啥这个 boost::asio::tcp::socket 可以重用?

Posted

技术标签:

【中文标题】为啥这个 boost::asio::tcp::socket 可以重用?【英文标题】:Why can this boost::asio::tcp::socket be re-used?为什么这个 boost::asio::tcp::socket 可以重用? 【发布时间】:2018-07-31 16:13:37 【问题描述】:

下面是一些代码from a boost::asio example。为什么在构造 chat_session 时移动 socket_ 成员是可以的,如果处理程序底部的递归调用将在下次接受发生时将相同的 tcp::socket 传递出去?我认为在移动操作之后,对象不再可以安全使用。

class chat_server

public:
  chat_server(boost::asio::io_service& io_service,
      const tcp::endpoint& endpoint)
    : acceptor_(io_service, endpoint),
      socket_(io_service)
  
    do_accept();
  

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

          do_accept();
        );
  

  tcp::acceptor acceptor_;
  tcp::socket socket_;
  chat_room room_;
;

【问题讨论】:

【参考方案1】:

代码等价于执行以下操作:

some_class o;
while ( true )

  // assign a new instance of some_class to the o variable, calling o.bar() is valid
  o = some_class(...);
  foo(std::move(o));
  // o is no longer valid calling o.bar() would fail

async_accept 的调用将套接字重新初始化为可以使用的有效值。移动的对象处于未指定(但有效)的状态,该状态是什么取决于该对象的实现者。对于asio::tcp::socket,状态是未初始化的套接字,可用于新连接。

【讨论】:

【参考方案2】:

你是对的,套接字对象在移动后不可用。

但是调用您的 lambda 的代码将创建一个 new 套接字并使用该新套接字初始化您的变量 socket_。所以下次调用你的 lambda 时,它实际上是一个 不同的 套接字。

【讨论】:

除了chat_server 的构造函数之外,我没有看到任何地方创建了新的套接字。 @JimHunziker 它发生在幕后,在调用底层网络代码的代码中。基本上,发生的事情是一个赋值:socket_ = new_socket_object;(或者可能是一个移动而不是简单的赋值)。【参考方案3】:

标准规定,“移出”对象必须至少处于有效的未指定状态。

移出的套接字可以安全使用,因为它的状态在文档中明确指定:

Following the move, the moved-from object is in the same state as if constructed using the basic_stream_socket(io_context&) constructor.

【讨论】:

以上是关于为啥这个 boost::asio::tcp::socket 可以重用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个函数序言中没有“sub rsp”指令,为啥函数参数存储在负 rbp 偏移量?

为啥这个正则表达式不匹配这个文本?

为啥这个变量还活着?

为啥 println() 打印这个?

为啥这个函数会返回这个值? [复制]

为啥这个例子不离开