簡體   English   中英

在 Linux 中將 fork() + execlp 與 boost::asio 一起使用時出現地址重用錯誤

[英]address reuse error when using fork() + execlp with boost::asio in Linux

我有一個程序,它在 TCP 端口上偵聽特定字符串並使用execlp調用啟動應用程序。 我正在做一個fork()在這個execlp調用之前啟動一個子進程。 在此啟動后,父進程再次開始偵聽同一端口。 我正在關閉子進程中的套接字。

我已經在boost::asio::tcp_socket上編寫了一個包裝器,在綁定套接字之前,我將addr_reuse選項設置為true

現在我的問題是在 Linux 中,我在幾次啟動應用程序后收到地址重用錯誤。 在我的程序中,它不斷嘗試接受連接(或者更准確地說是嘗試安排接受到boost::asio::io_service ),直到綁定然后接受成功。 所以我在這個循環中收到錯誤。

奇怪的是,如果我關閉(或殺死)啟動的可執行文件,這個錯誤就會停止,這意味着bind成功。 我確信在啟動的應用程序中沒有在任何地方使用相同的端口。 我正在使用異步套接字操作。 知道為什么我會收到此錯誤嗎?

這是我在套接字上接受的方式:(在開始新的接受之前,我還在boost::asio::tcp_socket(_tcpSocket)共享指針上調用了 reset。)

boost::asio::ip::tcp::endpoint endPoint(boost::asio::ip::tcp::v4(), port);
_acceptor.reset ( new boost::asio::ip::tcp::acceptor( *_ioService.get() ) );
_acceptor->open( endPoint.protocol() );
_acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));

boost::system::error_code ec;
_acceptor->bind(endPoint, ec);
if ( ec.value() != boost::system::errc::success )
{
    ec.clear();
    _acceptor->close(ec);
    close();
    return false;
}

ec.clear();
_acceptor->listen(boost::asio::socket_base::max_connections, ec);
if ( ec.value() != boost::system::errc::success )
{
    return false;
}
_acceptor->async_accept(*_tcpSocket,
                        boost::bind(&TCPSocket::_handleAsyncAccept,
                                    this,
                                    boost::asio::placeholders::error) );

這是我如何分叉:

pid_t pid = fork();
switch (pid)
{
    case 0:
    {
        /// close all sockets for child process. as it might cause addr reuse error in parent process
        _asyncNO->closeAll();
        std::string binary = "<binaryName>";
        std::string path = "<binaryPath>";
        if ( execlp( path.c_str(), binary.c_str(), controllerIP.c_str(), (char *)0 ) == -1 )
        {
            LOG_ERROR("System call failed !!")
        }
    }
    break;

    default:
}

為簡單起見,我刪除了日志記錄。

正如@TannerSansbury 在評論中所說,這可能是因為 Boost.Asio 需要通知fork()

有關使用 Boost.Asio 進行分叉的文檔的較新版本。

相關部分轉載於此:

Boost.Asio 支持使用fork()系統調用的程序。 如果程序在適當的時間調用io_service.notify_fork() ,Boost.Asio 將重新創建任何內部文件描述符(例如用於喚醒反應器的“自管道技巧”描述符)。 通知通常執行如下:

io_service_.notify_fork(boost::asio::io_service::fork_prepare);
if (fork() == 0)
{
  io_service_.notify_fork(boost::asio::io_service::fork_child);
  // ...
}
else
{
  io_service_.notify_fork(boost::asio::io_service::fork_parent);
  // ...
}

用戶定義的服務也可以通過覆蓋io_service::service::fork_service()虛擬函數來感知 fork。

請注意,通過 Boost.Asio 的公共 API 可訪問的任何文件描述符(例如, basic_socket<>posix::stream_descriptor等底層的描述符)在 fork 期間不會更改。 根據需要管理這些是程序的責任。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM