[英]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 支持使用
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.