提升io_service没有重置

时间:2017-08-10 15:08:23

标签: c++ sockets boost

我正在尝试为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秒后) 取消(立即) 超时(立即) 取消(立即) 超时(立即) 取消(立即) 超时(立即) ...

任何人都可以帮助发现我做错了吗?

2 个答案:

答案 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;
}