我正在尝试为boost套接字实现ConnectWithTimeout函数。所以我使用了我发现here的一个例子。这在第一次尝试时非常有效,但是io_service.run_one()会立即返回超时或取消错误。
这是我的代码
using NetStatus = boost::system::error_code;
NetStatus handleWait(const NetStatus& error)
{
return boost::asio::error::timed_out;
}
NetStatus handleConnect(const NetStatus& error)
{
// The async_connect() function automatically opens the socket at the start
// of the asynchronous operation. If the socket is closed at this time then
// the timeout handler must have run first.
if (!m_socket.is_open())
return boost::asio::error::timed_out;
// Otherwise, a connection has been established. Update the timer state
// so that the timeout handler does not close the socket.
m_connectionTimeoutTimer.cancel();
return error;
}
void connectWithTimeout(boost::asio::ip::tcp::endpoint& endpoint, NetStatus& e)
{
// Stop last time's waiting objects
m_socket.cancel()
m_connectionTimeoutTimer.cancel();
m_ioService.stop();
m_ioService.reset();
// Set-up new objects to wait
m_connectionTimeoutTimer.expires_from_now(boost::posix_time::seconds(5));
m_connectionTimeoutTimer.async_wait([this, &e](const NetStatus& error) { e = handleWait(error); } );
m_socket.async_connect(endpoint, [this, &e](const NetStatus& error) { e = handleConnect(error); } );
// Block until one of them is done
m_ioService.run_one(e);
}
boost::asio::ip::tcp::socket m_socket;
boost::asio::deadline_timer m_connectionTimeoutTimer;
我在循环中运行此结果时看到的结果是: 超时(按预期5秒后) 取消(立即) 超时(立即) 取消(立即) 超时(立即) 取消(立即) 超时(立即) ...
任何人都可以帮助发现我做错了吗?
答案 0 :(得分:0)
你是否在每个循环之间关闭套接字?您在同一个async_connect
实例上调用m_socket
,但我没有看到套接字关闭的位置。您可能在尝试连接已打开的套接字时出错。请尝试使用m_socket.close()
代替m_socket.cancel()
。
答案 1 :(得分:0)
好的,所以我找到了答案,似乎从io_service中获取处理程序的唯一方法是使用run或run_one调用它,reset等不会这样做。是我感兴趣的最终代码:
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/timer/timer.hpp>
std::string bindToIp;
std::string ip;
int port;
auto tcpConnectionTrials = 5ul;
using NetStatus = boost::system::error_code;
boost::asio::io_service m_ioService;
boost::asio::ip::tcp::socket m_socket(m_ioService);
boost::asio::deadline_timer connectionTimeoutTimer(m_ioService);
bool isTimedOut = false;
void handleWait(boost::asio::ip::tcp::socket& socket, const NetStatus& error)
{
if (error != boost::asio::error::operation_aborted)
{
isTimedOut = true;
socket.cancel();
socket.close();
}
}
void handleConnect(boost::asio::ip::tcp::socket& socket, const NetStatus& error)
{
if (error != boost::asio::error::operation_aborted)
{
// The async_connect() function automatically opens the socket at the start
// of the asynchronous operation. If the socket is closed at this time then
// the timeout handler must have run first.
if (socket.is_open())
{
connectionTimeoutTimer.cancel();
}
}
}
void connectWithTimeout(boost::asio::ip::tcp::socket& socket,
boost::asio::deadline_timer& connectionTimeoutTimer,
boost::asio::io_service& m_ioService,
boost::asio::ip::tcp::endpoint& endpoint,
NetStatus& e)
{
isTimedOut = false;
// Set-up new objects to wait
connectionTimeoutTimer.expires_from_now(boost::posix_time::seconds(5));
connectionTimeoutTimer.async_wait([&socket](const NetStatus& error) { handleWait(socket, error); } );
socket.async_connect(endpoint, [&socket, &e](const NetStatus& error) { e = error; handleConnect(socket, error); } );
// Block until one of them is done
m_ioService.run();
if (isTimedOut)
{
e = boost::asio::error::timed_out;
}
m_ioService.reset();
}
NetStatus connect()
{
NetStatus e;
boost::asio::ip::tcp::endpoint remoteEndpoint(boost::asio::ip::address_v4::from_string(ip.c_str()), port);
boost::asio::ip::tcp::endpoint localEndpoint(boost::asio::ip::address_v4::from_string(bindToIp.c_str()), 0);
std::cout << "Open socket: " << std::endl;
if (m_socket.open(boost::asio::ip::tcp::v4(), e))
{
std::cout << "Socket " << ": could not open!!!" << std::endl;
return e;
}
m_socket.set_option(boost::asio::socket_base::reuse_address(true));
m_socket.set_option(boost::asio::ip::tcp::no_delay(true));
std::cout << " binds to " << bindToIp << std::endl;
m_socket.bind(localEndpoint);
std::cout << " connect to " << ip << std::endl;
connectWithTimeout(m_socket, connectionTimeoutTimer, m_ioService, remoteEndpoint, e);
return e;
}
int main(int argc, char *argv[])
{
bindToIp = argv[1];
ip = argv[2];
port = atoi(argv[3]);
for(int i =0; i < 10; i++)
{
auto e = connect();
if (!e)
{
std::cout << "GOOD!" << std::endl;
break;
}
else
{
std::cout << "Failed: " << e.message() << std::endl;
}
m_socket.close();
}
std::cout << "DONE!" << std::endl;
return 0;
}