我目前使用Windows 7 64位,MSVC2010和Boost.Asio 1.57。我想连接到超时的TCP服务器。如果超时到期,我应该尽快关闭连接,因为IP地址(由用户选择)可能是错误的。
我知道我应该使用异步请求,因为同步请求没有包含超时选项。所以我正在使用带外部超时的async_connect。这是我在很多地方找到的解决方案,包括stackoverflow。
问题是以下代码的行为与我希望的不同。 socket.close()不会“取消”async_connect。使用我的计算机,关闭套接字需要大约15秒才能完成,这使得我的程序暂时无法响应... 我希望有一个不错的超时(约3秒)并在此时间后关闭套接字,以便用户可以尝试连接另一个IP地址(来自HMI)
#include <iostream>
#include <boost\asio.hpp>
#include <boost\shared_ptr.hpp>
#include <boost\bind.hpp>
using boost::asio::ip::tcp;
class tcp_client
{
public:
tcp_client(boost::asio::io_service& io_service, tcp::endpoint& endpoint, long long timeout = 3000000)
:m_io_service (io_service),
m_endpoint(endpoint),
m_timer(io_service),
m_timeout(timeout)
{
connect();
}
void stop()
{
m_socket->close();
}
private:
void connect()
{
m_socket.reset(new tcp::socket(m_io_service));
std::cout << "TCP Connection in progress" << std::endl;
m_socket->async_connect(m_endpoint,
boost::bind(&tcp_client::handle_connect, this,
m_socket,
boost::asio::placeholders::error)
);
m_timer.expires_from_now(boost::posix_time::microseconds(m_timeout));
m_timer.async_wait(boost::bind(&tcp_client::HandleWait, this, boost::asio::placeholders::error));
}
void handle_connect(boost::shared_ptr<tcp::socket> socket, const boost::system::error_code& error)
{
if (!error)
{
std::cout << "TCP Connection : connected !" << std::endl;
m_timer.expires_at(boost::posix_time::pos_infin); // Stop the timer !
// Read normally
}
else
{
std::cout << "TCP Connection failed" << std::endl;
}
}
public:
void HandleWait(const boost::system::error_code& error)
{
if (!error)
{
std::cout << "Connection not established..." << std::endl;
std::cout << "Trying to close socket..." << std::endl;
stop();
return;
}
}
boost::asio::io_service& m_io_service;
boost::shared_ptr<tcp::socket> m_socket;
tcp::endpoint m_endpoint;
boost::asio::deadline_timer m_timer;
long long m_timeout;
};
int main()
{
boost::asio::io_service io_service;
tcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("192.168.10.74"), 7171); // invalid address
tcp_client tcpc(io_service, endpoint);
io_service.run();
system("pause");
}
我找到的唯一解决方案是在许多线程中运行io_service:run(),并为每个连接创建一个新套接字。但是这个解决方案对我来说似乎没有用,因为我必须指定一些线程,而且我不知道用户将在HMI中输入多少错误的地址。是的,有些用户并不像其他用户那么聪明......
我的代码出了什么问题?如何以干净,快速的方式中断TCP连接?
祝你好运, Poukill
答案 0 :(得分:2)
代码没有任何基本错误,它完全符合您对Linux机箱的要求:
TCP Connection in progress
Connection not established...
Trying to close socket...
TCP Connection failed
real 0m3.003s
user 0m0.002s
sys 0m0.000s
注意:
您可能已成功为cancel()
功能添加stop()
来电:
void stop()
{
m_socket->cancel();
m_socket->close();
}
你应该检查超时的堕胎:
void HandleWait(const boost::system::error_code& error)
{
if (error && error != boost::asio::error::operation_aborted)
{
std::cout << "Connection not established..." << std::endl;
std::cout << "Trying to close socket..." << std::endl;
stop();
return;
}
}
否则成功连接后隐式取消定时器仍将关闭()套接字:)
如果要并行运行(多个)连接尝试,则不需要任何其他线程,甚至不需要多个io_service
。这是Boost Asio的本质:您可以在单个线程上执行异步IO操作。
这个答案给出了一个非常孤立的图片(即使连接是在那里使用ZMQ完成的):boost asio deadline_timer async_wait(N seconds) twice within N seconds cause operation canceled
另一个例子,这次是关于单个io_service
独立完成多个会话的时间:boost::asio::deadline_timer::async_wait not firing callback