boost :: asio - знать, когда соединение должно быть отключено / закрыто - PullRequest
4 голосов
/ 03 февраля 2012

Я реализую протокол (socks), который требует, чтобы мой сервер ретранслировал соединения, приходящие от клиента к месту назначения.

Я реализую часть ретрансляции, используя что-то вроде этого:

socket_.async_read_some(boost::asio::buffer(dataClient_, 1024),
boost::bind(&ProxySocksSession::HandleClientProxyRead, this,
 boost::asio::placeholders::error,
 boost::asio::placeholders::bytes_transferred));

remoteSock_.async_read_some(boost::asio::buffer(dataRemote_, 1024),
boost::bind(&ProxySocksSession::HandleRemoteProxyRead, this,
 boost::asio::placeholders::error,
 boost::asio::placeholders::bytes_transferred));

Конечно, есть больше кода - там есть обработчики, которые ретранслируют данные, поступающие из socket_ и отправляющие их в remoteSock_ и наоборот (все данные, поступающие из remoteSock_, передаются в гнездо _)

Я видел пример эхо-запроса асинхронного tcp-сервера (http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp)), и там была логика, когда для отключения соединения было просто удалить объект соединения - удалить это - (который закрыл принадлежащий ему сокет связи) когда в обработчике получено повышение :: system :: error_code.

Как мне самому заняться этим делом? На этот раз у меня есть данные, поступающие на 2 сокета, и если я не завершу чистое отключение, я мог бы закончить тем, что закрылся до того, как все данные были переданы (например, сокет со стороны клиента - socket_ - может закрыть соединение, но - remoteSock - все еще может пытаться отправить данные).

РЕДАКТИРОВАТЬ Я обновил свой код до такой степени, что, если я обнаружил, что один из обработчиков чтения / записи сокетов (remoteSock_ или socket_) сообщил о повышении :: system :: error_code, я делаю следующее в Чтобы отключить связь:

void ProxySocksSession::Shutdown()
{
    if (!shutdownInProgress_)
    {
        std::cout << "Shuting down ..." << std::endl;
        shutdownInProgress_ = true;
        remoteSock_.shutdown((boost::asio::ip::tcp::socket::shutdown_both));
        remoteSock_.close();
        socket_.shutdown((boost::asio::ip::tcp::socket::shutdown_both));
        socket_.close();
        parentConnection_.Shutdown();
    }
}

Проблема в том, что даже если я вызываю shutdown () и close () для сокетов, я все равно получаю вызовы обработчиков сокетов (они находятся в том же классе, ProxySocksSession). К тому времени, когда они появятся, мой экземпляр ProxySocksSession уже будет удален (удаление выполняется parentConnection_.Shutdown () сверху)

1 Ответ

2 голосов
/ 04 февраля 2012

Мне удалось найти решение, которое работает (не вызывает описанных проблем). Я также включил ниже скелет для функций обработчика, чтобы увидеть идею:

void ProxySocksSession::Start()
{
    socket_.async_read_some(boost::asio::buffer(dataClient_, 1024),
       boost::bind(&ProxySocksSession::HandleClientProxyRead, shared_from_this(),
           boost::asio::placeholders::error,
           boost::asio::placeholders::bytes_transferred));

    remoteSock_.async_read_some(boost::asio::buffer(dataRemote_, 1024),
           boost::bind(&ProxySocksSession::HandleRemoteProxyRead, shared_from_this(),
           boost::asio::placeholders::error,
           boost::asio::placeholders::bytes_transferred));
}

// received data from socks5 client - completion handler
void ProxySocksSession::HandleClientProxyRead(const boost::system::error_code& error,
      size_t bytes_transferred)
{
     if (!error && !this->shutdownInProgress_)
     {
         // relay data coming from client to remote endpoint -> async write to remoteSock_
         // async read some more data from socket_
      }
      else
      {
         Shutdown();
      }
 }

//received data from socks5 remote endpoint (socks5 client destination)
void ProxySocksSession::HandleRemoteProxyRead(const boost::system::error_code& error,
      size_t bytes_transferred)
{
     if (!error && !this->shutdownInProgress_)
     {
         // relay data coming from remote endpoint to client -> async write to socket__
         // async read some more data from remoteSock_
      }
      else
      {
         Shutdown();
      }
 }

void ProxySocksSession::Shutdown()
{
    if (!shutdownInProgress_)
    {
        std::cout << "Shuting down ..." << std::endl;
        shutdownInProgress_ = true;
        //remoteSock_.close(); -- no need as it is closed automatically as part of parentConnection_ shutdown/deletion
        //socket_.close(); -- no need as it is closed automatically as part of parentConnection_ shutdown/deletion
        parentConnection_.Shutdown();
    }
}

Клавиша - это тот факт, что я использовал shared_from_this () при передаче для привязки обработчиков завершения. Таким образом, я удостоверился, что удаление экземпляра ProxySocksSession было не выполнено экземпляром parentConnection_, который имел shared_ptr для ProxySocksSession до всех обработчиков ProxySocksSession были вызваны в то время как сокеты закрывались.

...