提升asio SO_REUSEPORT

时间:2016-01-04 17:32:57

标签: sockets boost

我正在使用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中使用此选项?

4 个答案:

答案 0 :(得分:3)

关于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));

答案 1 :(得分:1)

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构造函数,它接受一个布尔参数来设置重用标记。

答案 2 :(得分:1)

自己回答。

#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;
        }
    }
}

答案 3 :(得分: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选项。