【问题标题】:boost io_service doesn't resetboost io_service 不会重置
【发布时间】:2017-08-10 15:08:22
【问题描述】:

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

谁能帮忙找出我做错了什么?

【问题讨论】:

  • 我不明白你为什么在connectWithTimeout()函数中调用m_ioService.stop();m_ioService.reset();
  • 我试图让 io_service 停止从上一次运行中弹出事件,所以我通过运行 reset 和 stop 确保没有以前的处理程序在等待。

标签: c++ sockets boost


【解决方案1】:

您是否在每个循环之间关闭套接字?您在同一个 m_socket 实例上调用 async_connect,但我没有看到套接字关闭的位置。您可能在尝试连接已打开的套接字时遇到错误。试试m_socket.close() 而不是m_socket.cancel()

【讨论】:

  • 我按照您的建议将 m_socket.cancel() 替换为 m_socket.close() 并得到与以前相同的结果
【解决方案2】:

好的,所以我找到了答案,似乎从 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;
}

【讨论】:

  • 我发现该机制应该并且确实有效!这不是提升,而是驱动问题,因为我使用了一个特殊的驱动来提升套接字性能。
猜你喜欢
  • 2017-09-17
  • 2011-06-16
  • 2011-09-17
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-26
  • 2011-12-18
相关资源
最近更新 更多