Boost::ASIO 解析多个地址

问题描述 投票:0回答:1

我在使用 Boost::ASIO 解析多个地址时遇到一些问题。我可以调用 async_resolve 一次,获取端点,然后毫无问题地连接到它。但是,如果我想稍后再次调用 async_resolve,async_resolve 将永远挂起并且永远不会调用我的事件处理程序。

有没有办法完成或者关闭之前的async_resolve?还是别的什么?

hostResolver = new boost::asio::ip::tcp::resolver(*internalEventPump->getIoService());
    
hostResolver->async_resolve(boost::asio::ip::tcp::v4(), hostName, portString,
    boost::bind(&DTcpSocket::resolveFinished, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator));

...

void DTcpSocket::resolveFinished(const boost::system::error_code &errorCode,
                                 boost::asio::ip::tcp::resolver::iterator iterator)
{
    endPointIter = iterator;

    if (errorCode)
    {
        errMsg = "Couldn't resolve hostname: " + errorCode.message();
        connectionHandler(errMsg, DA_HOSTNAME_ERROR);
    }
    else
    {
        boost::asio::ip::tcp::endpoint endpoint = *endPointIter;
        cout << endpoint.address() << endl;

        endPointIter++;//we'll try to connect to this endpoint if the first endpoint failed.
        clientSocket->async_connect(endpoint, boost::bind(&DTcpSocket::connectFinished, this,
                                                          boost::asio::placeholders::error));
    }
}//resolveFinished
c++ boost-asio resolve
1个回答
0
投票

根据 sehe 的评论,这确实是一个可以用 work_guard 解决的问题。演示该问题的完整示例,并在评论中修复:

#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <chrono>
#include <iostream>
#include <thread>

using namespace std;

static boost::asio::ip::tcp::resolver* HostResolver = nullptr;
static boost::asio::ip::tcp::resolver::iterator EndPointIter = boost::asio::ip::tcp::resolver::iterator();
static boost::asio::ip::tcp::socket* ClientSocket = nullptr;
static bool ConnectInProgress = false;
static const int MAX_ASIO_EVENTS = 1000;
static const unsigned int BUFFER_SIZE = 16384;
static unsigned char* ReceiveBuffer;

void StartConnect();
void ResolveFinished(const boost::system::error_code &errorCode, boost::asio::ip::tcp::resolver::iterator iterator);
void ConnectionFinished(const boost::system::error_code &errorCode);
void ConnectFinished(const boost::system::error_code &errorCode);
void ReceiveFinished(const boost::system::error_code &errorCode, size_t bytesReceived);
bool Close();
bool CurrentlyConnected();

int main(int argc,
         char* argv[])
{
    ReceiveBuffer = new unsigned char[BUFFER_SIZE];
    boost::asio::io_service* ioService = new boost::asio::io_service;
    ClientSocket = new boost::asio::ip::tcp::socket(*ioService);
    HostResolver = new boost::asio::ip::tcp::resolver(*ioService);
    
    //The fix:
    //boost::asio::executor_work_guard<decltype(ioService->get_executor())> work{ioService->get_executor()};
 
    StartConnect();
    
    while (true)
    {    
        int eventsRun = 0;
            
        try
        {
            while (ioService->poll_one() > 0 && eventsRun < MAX_ASIO_EVENTS)
                eventsRun++;
        
        }
        catch (exception &e)
        {
            cerr << "ASIO error " << e.what() << endl;
            return 1;
        }
        
        if (!ConnectInProgress)
        {
            if (!CurrentlyConnected())
                StartConnect();
        }
        
        if (eventsRun == 0)            
            this_thread::sleep_for(chrono::milliseconds(1));
    }
    
    delete ClientSocket;
    delete HostResolver;
    delete ioService;
    delete[] ReceiveBuffer;
    
    return 0;
}//main

bool CurrentlyConnected()
{
    boost::system::error_code errorCode;//error code returned by boost

    if (ClientSocket->is_open())
    {
        ClientSocket->remote_endpoint(errorCode);
        if (!errorCode)
            return true;
    }
    
    return false;
}//CurrentlyConnected

void StartConnect()
{
    this_thread::sleep_for(chrono::milliseconds(2000));
    ConnectInProgress = true;
    cout << "Running async_resolve..." << endl;
    HostResolver->async_resolve(boost::asio::ip::tcp::v4(), "127.0.0.1", "5127", &ResolveFinished);
}//StartConnect

void ResolveFinished(const boost::system::error_code &errorCode,
                     boost::asio::ip::tcp::resolver::iterator iterator)
{
    cout << "ResolveFinished() called" << endl;
    EndPointIter = iterator;

    if (errorCode)
    {
        cout << "Couldn't resolve hostname: " << errorCode.message() << endl;
        ConnectInProgress = false;
    }
    else
    {
        boost::asio::ip::tcp::endpoint endpoint = *EndPointIter;
        EndPointIter++;
        
        cout << "Running async_connect to " << endpoint.address() << endl;
        ClientSocket->async_connect(endpoint, &ConnectFinished);
    }
}//ResolveFinished

void ConnectFinished(const boost::system::error_code &errorCode)
{
    cout << "ConnectFinished() called" << endl;

    boost::asio::ip::tcp::endpoint endpoint;//the IP address and port number to connect to

    //### Try a different endpoint if we couldn't connect ###
    if (errorCode)
    {
        if (errorCode != boost::asio::error::operation_aborted)
        {
            //Verify that there's another endpoint
            if (EndPointIter == boost::asio::ip::tcp::resolver::iterator())
            {
                cout << "Couldn't connect: " + errorCode.message() << endl;
                ConnectInProgress = false;
                return;
            }

            //Close the socket
            if (!Close())
            {
                ConnectInProgress = false;
                return;
            }

            //Start another asynchronous connect
            endpoint = *EndPointIter;
            EndPointIter++;

            cout << "Running async_connect to " << endpoint.address() << endl;
            ClientSocket->async_connect(endpoint, &ConnectFinished);
        }
    }

    //### We connected successfully ###
    else
    {
        cout << "We connected!" << endl;
        ConnectInProgress = false;
        ClientSocket->async_receive(boost::asio::buffer(ReceiveBuffer, BUFFER_SIZE), &ReceiveFinished);
    }
}//ConnectFinished

void ReceiveFinished(const boost::system::error_code &errorCode,
                     size_t bytesReceived)
{
    if (errorCode)
    {
        if (errorCode != boost::asio::error::operation_aborted)
        {
            cout << errorCode.message() << endl;
            Close();
        }
    }
    else
    {
        if (bytesReceived > 0)
            ClientSocket->async_receive(boost::asio::buffer(ReceiveBuffer, BUFFER_SIZE), &ReceiveFinished);

        else
        {
            cout << "Received zero bytes." << endl;
            Close();
        }
    }
}//ReceiveFinished

bool Close()
{
    boost::system::error_code errorCode;

    cout << "Close() called" << endl;

    if (ClientSocket->is_open())
    {
        ClientSocket->shutdown(boost::asio::ip::tcp::socket::basic_stream_socket::shutdown_both, errorCode);
        if (errorCode)
        {
            cout << "Got an error invoking shutdown()" << endl;
            boost::system::error_condition theError = errorCode.default_error_condition();

            if (theError.value() != boost::system::errc::not_connected)
            {
                cout << "Couldn't shutdown socket: " << theError.message() << endl;
                return false;
            }
        }

        ClientSocket->close(errorCode);
        if (errorCode)
        {
            boost::system::error_condition theError = errorCode.default_error_condition();

            cout << "Couldn't close socket: " << theError.message() << endl;
            return false;
        }
    }
    else
        cout << "The socket is already closed" << endl;

    return true;
}//Close
© www.soinside.com 2019 - 2024. All rights reserved.