【问题标题】:boost asio SO_REUSEPORT提升 asio SO_REUSEPORT
【发布时间】:2016-04-08 09:21:02
【问题描述】:

我正在使用 boost 库开发多进程套接字服务器。

每个进程运行一个io_service

我希望这个进程都接受同一个端口。

我知道SO_REUSEPORT(在 linux 内核 3.9 之后)会有所帮助。

喜欢这个 python 脚本

import socket                                                                                                                                                       

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                                                                                                               
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)                                                                                                             

s.bind(('0.0.0.0', 9091))
s.listen(1)

while True:
    conn, addr = s.accept()
    print "new connection"
    while True:
        data = conn.recv(100)
        print "got data", data
        if not data or data == 'exit':
            break
    conn.close()

但是我不知道如何在 boost asio io_service 中使用这个选项?

【问题讨论】:

  • 你可以搜索这个。它经常被讨论(强调何时使用/正确性)。在这个过程中你可以看到设置reuse-addr/reuse-port的各种方式。其中一些是依赖于平台的 IIRC
  • @sehe 我在 google 上搜索过,但没有帮助

标签: sockets boost


【解决方案1】:

对于 2019 年阅读本文的人:Asio 现在在 boost/asio/detail/impl/socket_ops.ipp 中包含一个解决方法:

#if defined(__MACH__) && defined(__APPLE__) \
  || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
    // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
    // need to also set SO_REUSEPORT on BSD-based platforms.
    if ((state & datagram_oriented)
        && level == SOL_SOCKET && optname == SO_REUSEADDR)
    {
      call_setsockopt(&msghdr::msg_namelen, s,
          SOL_SOCKET, SO_REUSEPORT, optval, optlen);
    }
#endif

因此,socket_->set_option(udp::socket::reuse_address(true)); 将在需要时自动设置SO_REUSEPORT 选项。

【讨论】:

    【解决方案2】:

    从 boost/asio/socket_base.hpp 如何定义reuse_address 开始,我是这样做的:

    typedef boost::asio::detail::socket_option::boolean<SOL_SOCKET, SO_REUSEPORT> reuse_port;
    socket_.set_option(reuse_port(true));
    

    【讨论】:

      【解决方案3】:

      我自己回答。

      #include <iostream>
      #include <string>
      #include <array>
      #include <boost/asio.hpp>
      #include <arpa/inet.h>
      
      
      using boost::asio::ip::tcp;
      
      int main()
      {
          boost::asio::io_service io;
          tcp::acceptor acceptor(io);
          acceptor.open(tcp::v4());
      
          int one = 1;
          setsockopt(acceptor.native_handle(), SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &one, sizeof(one));
      
          acceptor.bind(tcp::endpoint(tcp::v4(), 9091));
          acceptor.listen();
      
          std::cout << "start" << std::endl;
          for(;;)
          {
              tcp::socket socket(io);
      
              acceptor.accept(socket);
              std::cout << "new connections" << std::endl;
              for(;;)
              {                                                                                                                                                               
                  std::array<char, 4> buf;
                  boost::system::error_code error;
                  boost::asio::read(socket, boost::asio::buffer(buf), error);
                  if(error)
                  {
                      std::cout << "read error: " << error << std::endl;
                      break;
                  }
                  std::cout << "read: " << std::string(buf.data()) << std::endl;
              }
          }
      }
      

      【讨论】:

      • 您应该包含一个更具描述性的摘要,说明您为使其工作所做的更改,而不是代码块和“我自己回答”的字样。
      【解决方案4】:

      HTTP 服务器示例显示了一种方式:http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/example/cpp11/http/server/server.cpp

        // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
        boost::asio::ip::tcp::resolver resolver(io_service_);
        boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve({address, port});
        acceptor_.open(endpoint.protocol());
        acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
        acceptor_.bind(endpoint);
        acceptor_.listen();
      

      IIRC 还有一个 acceptor 构造函数,它接受一个布尔参数来设置重用标志。

      【讨论】:

      • 我需要,REUSE_PORT,而不是 REUSE_ADDRESS
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-10
      • 2016-05-02
      • 2010-12-16
      相关资源
      最近更新 更多