deadline_timer
接続タイムアウトとして aを使用して、boost asio を使用して 3 つの TCP ソケットに非同期的に接続するプログラムがあります。Windowsでは、すべてが期待どおりに機能します。接続は 5 秒後にタイムアウトします。ただし、Unix (WSL 上の Ubuntu、Linux Mint VM、macOS) では、connectDeadline は起動しません。async_connect 操作は永久に実行されます。これが機能しないのはなぜですか? また、これを Unix でも機能させるにはどうすればよいですか?
コード: 注: connect はメイン スレッド (GUI スレッドでもあります) から呼び出されます。
#include "NetManager.h"
NetManager::NetManager(NetManagerListener& listener) : listener(listener),
connectDeadline(io),
socket1(io),
socket2(io),
socket3(io),
asioThread(&NetManager::handleAsioOperations, this){
}
NetManager::~NetManager() {
running = false;
io.stop();
asioThread.join();
}
void NetManager::connect(){
connectCounter = 0;
hasHandledConnectError = false;
socket1.async_connect(
tcp::endpoint(boost::asio::ip::address::from_string(IP_STRING), PORT_1),
boost::bind(&NetManager::handleConnect, this, _1));
socket2.async_connect(
tcp::endpoint(boost::asio::ip::address::from_string(IP_STRING), PORT_2),
boost::bind(&NetManager::handleConnect, this, _1));
socket3.async_connect(
tcp::endpoint(boost::asio::ip::address::from_string(IP_STRING), PORT_3),
boost::bind(&NetManager::handleConnect, this, _1));
connectDeadline.expires_from_now(boost::posix_time::seconds(CONNECT_TIMEOUT));
connectDeadline.async_wait(boost::bind(&NetManager::handleConnectTimeout, this, _1));
}
void NetManager::disconnect(){
//NOTE: Close also cancels incomplete async operations
socket1.close();
socket2.close();
socket3.close();
}
////////////////////////////////////////////////////////////////////////
/// ASIO Handlers
////////////////////////////////////////////////////////////////////////
void NetManager::handleAsioOperations(){
while(running){
io.run(); // Run any async operations
}
}
void NetManager::handleConnect(const boost::system::error_code &ec){
// When connections are canceled the handler is called with operation_aborted. No need to respond to that.
if(ec && ec != boost::asio::error::operation_aborted && !hasHandledConnectError){
hasHandledConnectError = true; // Likely to be 3 repeated errors. Make sure to only handle the first one
cerr << "Connect Failed: " << ec.message() << endl;
connectDeadline.cancel(); // Don't fire the timeout
disconnect(); // Disconnect any already connected sockets
connectedToRobot = false;
listener.onConnect(false);
}else if (!ec){
connectCounter++;
}
if(connectCounter == 3){
cout << "Successful connect" << endl;
connectDeadline.cancel(); // Don't fire the timeout
connectedToRobot = true;
listener.onConnect(true);
}
}
void NetManager::handleConnectTimeout(const boost::system::error_code &ec){
if(ec != boost::asio::error::operation_aborted){
cerr << "Connect timed out." << endl;
disconnect(); // Disconnect any already connected sockets
connectedToRobot = false;
listener.onConnect(false);
}
}
編集:
紛らわしいことに、これは Unix OS では問題なく動作します。
#include <boost/asio.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <iostream>
#include <thread>
using namespace boost::asio;
using namespace boost::asio::ip;
int main(){
io_service io;
deadline_timer timer1(io);
tcp::socket sock(io);
timer1.expires_from_now(boost::posix_time::seconds(3));
sock.async_connect(tcp::endpoint(boost::asio::ip::address::from_string("10.50.30.1"), 8090), [](const boost::system::error_code &ec){
std::cout << "SocketError: " << ec.message() << std::endl;
});
timer1.async_wait([&](const boost::system::error_code &ec){
std::cout << "First timer" << std::endl;
sock.close();
});
std::thread worker([&](){
while(true){
io.run();
}
});
worker.detach();
while(true){} // Simulate the unavailable main (GUI) thread
}
出力:
First timer
SocketError: Operation canceled