Asio:'已经在使用的地址'在Bind,但我仍然可以连接

时间:2016-02-12 15:06:09

标签: sockets c++11 tcp boost-asio

我有什么似乎不是问题,但我不理解错误。基本上,我一直在努力研究优雅的代码#34;关闭两端的tcp套接字。在我的程序结束时,双方都关闭了我的套接字,然后关闭它们。快速重启,这是我试图解决的问题,因为套接字在两边挥之不去而导致崩溃的更严重的问题不再发生。关闭/然后关闭似乎在这方面工作。

然而,我得到了#34;地址已经在使用"仍然,这通常使我无法连接。现在我能够在错误之后连接就好了。我已经在graceful shutdownreuse address等主题上阅读了很多内容。而且我想我的问题是,如果套接字错误绑定("地址已经在使用"),在成功打开后,它是否可能连接到端点?换句话说,如果地址 实际上已经在使用中,那么连接是如何进行的?另外值得注意的是,重用地址在这种情况下不起作用。因为我使用相同的套接字设置,本地/远程地址和ip。

1 个答案:

答案 0 :(得分:1)

无法bind()套接字到地址不会使底层套接字无效。因此,connect()操作将继续使用未绑定的套接字,推迟到内核绑定到本地端点。

以下是完整示例demonstrating此行为:

#include <boost/asio.hpp>
#include <boost/bind.hpp>

// This example is not interested in all handlers, so provide a noop function
// that will be passed to bind to meet the handler concept requirements.
void noop() {}

int main()
{
  using boost::asio::ip::tcp;

  // Create all I/O objects.
  boost::asio::io_service io_service;
  tcp::acceptor acceptor(io_service, {tcp::v4(), 0});
  tcp::socket server(io_service, tcp::v4());

  // Open socket1, binding to a random port.
  tcp::socket socket1(io_service, {boost::asio::ip::address_v4::any(), 0});
  tcp::socket socket2(io_service); // non-open

  // Explicitly open client2, which will bind it to the any address.
  boost::system::error_code error;  
  socket2.open(tcp::v4(), error);
  assert(!error);
  assert(socket2.local_endpoint().port() == 0);

  // Attempt to bind socket2 to socket1's address will fail with
  // an already in use error, leaving socket2 bound to the any endpoint.
  // (e.g. a failed bind does not have side effects on the socket) 
  socket2.bind(socket1.local_endpoint(), error);
  assert(error == boost::asio::error::address_in_use);
  assert(socket2.local_endpoint().port() == 0);

  // Connect will defer to the kernel to bind the socket.
  acceptor.async_accept(server, boost::bind(&noop));  
  socket2.async_connect(acceptor.local_endpoint(), 
    [&error](const boost::system::error_code& ec) { error = ec; });
  io_service.run();
  io_service.reset();
  assert(!error);
  assert(socket2.local_endpoint().port() != 0);
}