【问题标题】:boost::acceptor::cancel doesn't work as expectedboost::acceptor::cancel 没有按预期工作
【发布时间】:2014-11-14 11:56:54
【问题描述】:

我已经使用 boost 实现了一个 SocketServer。此 SocketServer 的工作原理如下:

  • 接受一定时间的连接
  • 超时后停止处理套接字

这是我的代码:

ServerSocket::ServerSocket(unsigned int port)
{
    _io_service.reset(new boost::asio::io_service()) ;
    _endpoint.reset(new boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port));
    _acceptor.reset(new boost::asio::ip::tcp::acceptor(*_io_service, *_endpoint)) ;
    _newConnection = false; 
}

bool ServerSocket::accept(boost::asio::ip::tcp::socket& socket, int timeout)
{
    _newConnection = false;
    _acceptor->async_accept(socket, boost::bind(&ServerSocket::handleAccept, this, &socket));
    _io_service->reset();

    if (timeout > 0)
    {
        int incrementation = 1;
        int time_spent = 0;
        while (time_spent < timeout && !_io_service->poll_one())
        {
            time_spent += incrementation;
            sleep(incrementation);
        }
    }
    else
    {
        _io_service->run_one();
    }

    if (!_newConnection)
    {
        _acceptor->cancel();
    }

    return _newConnection;

}

void ServerSocket::handleAccept(boost::asio::ip::tcp::socket* pSocket)
{
    _newConnection = true;
};

我的问题如下:当我用超时和套接字 A 调用 accept() 时。如果达到超时,我用新的套接字 B 再次调用它,如果此时 accept() 有效,我处理 A而不是 B。

如果缺少信息,请告诉我。

【问题讨论】:

  • 你的套接字类在哪里?你为什么调用io_service->reset()?如果您想“单步执行”服务,只需运行同步方法而不是异步方法
  • 我不想使用同步方法,因为我希望能够随时中断我的服务器

标签: c++ sockets boost


【解决方案1】:

您可以简单地使用 io_service 的任务循环,并使用截止时间计时器来取消接受器上的操作。

Live On Coliru

#include <boost/asio.hpp>
#include <boost/bind.hpp>

using namespace boost;
using asio::ip::tcp;

struct ServerSocket
{
    asio::io_service _io_service;
    tcp::endpoint _endpoint;
    tcp::acceptor _acceptor;
    asio::deadline_timer _timer;
    bool _newConnection;

    ServerSocket(unsigned int port)
        : _io_service(),
          _endpoint(tcp::v4(), port),
          _acceptor(_io_service, _endpoint),
          _timer(_io_service),
          _newConnection(false)
    {
    }

    void timer_expired(boost::system::error_code ec)
    {
        if (!ec)
        {
            _acceptor.cancel();
        }
    }

    bool accept(boost::asio::ip::tcp::socket& socket, int timeout)
    {
        _newConnection = false;
        _io_service.reset();
        _timer.expires_from_now(boost::posix_time::seconds(timeout));
        _timer.async_wait(boost::bind(&ServerSocket::timer_expired, this, asio::placeholders::error));
        _acceptor.async_accept(socket, boost::bind(&ServerSocket::handleAccept, this, &socket, asio::placeholders::error));

        _io_service.run();

        return _newConnection;
    }

    void handleAccept(boost::asio::ip::tcp::socket* pSocket, boost::system::error_code ec)
    {
        if (!ec)
        {
            _timer.cancel();
            _newConnection = true;
        }
    };
};

int main()
{
    ServerSocket s(6767);

    tcp::socket socket(s._io_service);

    if (s.accept(socket, 3))
        std::cout << "Accepted connection from " << socket.remote_endpoint() << "\n";
    else
        std::cout << "Timeout expired\n";
}

如果只是执行!ec,您可能应该明确检查 operation_canceled 错误代码,但我会将其作为练习留给读者。

【讨论】:

  • 非常感谢。这确实是用户提升deadline_timer而不是手动等待的更好主意......
猜你喜欢
  • 2023-03-08
  • 2021-10-19
  • 2020-03-18
  • 2012-06-14
  • 2014-11-15
  • 1970-01-01
  • 2012-07-02
  • 2011-09-07
  • 2013-03-03
相关资源
最近更新 更多