boost :: asio и асинхронный поток SSL: как определить конец данных / закрытие соединения?

Я пытаюсь подружиться с asio и SSL. Все идет хорошо, но неудобства доставляет одно: как определить, если одноранговое тесное соединение, и отличить его от ситуации когда партнер просто делает небольшой перерыв в отправке данных, стремясь продолжить через несколько секунд?

  • boost 1.48
  • OpenSSL 1.0.0e
  • Скомпилирован в 32-битный код с использованием VS10
  • Работает на W7 x64.

Мое замешательство связано с тем, что поведение asio для обычный сокет и SSL-поток. Если я использую tcp :: socket - я получаю ошибку EOF при закрытии однорангового соединения. Но для boost :: asio :: ssl :: stream - это не тот случай. Вместо этого async_read_some возвращает 0 в качестве переданных байтов, и если я попытаюсь продолжить чтение из потока SSL - возвращает short_error ( http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/streams.html ).

Итак, вопрос: это ожидаемое поведение, или я что-то неправильно настроил?

Фрагмент клиентского кода:

class client
{
public:

    // bla-bla-bla-bla-bla ....
    //
   void handle_write(const boost::system::error_code& error)
   {
       if (!error)
       {
           socket_.async_read_some(boost::asio::buffer(reply_, max_length),
               boost::bind(&client::handle_read, this,
               boost::asio::placeholders::error,
               boost::asio::placeholders::bytes_transferred));
       }
       else
       {
           std::cout << "Write failed: " << error.message() << "\n";
       }
   }

   void handle_read(const boost::system::error_code& error,
                   size_t bytes_transferred)
   {

       std::cout << "Bytes transfered: " << bytes_transferred << "\n";
       if (!error)
       {
           std::cout << "Reply: ";
           std::cout.write(reply_, bytes_transferred);
           std::cout << "\n";

           std::cout << "Reading...\n";
           socket_.async_read_some(boost::asio::buffer(reply_, max_length),
               boost::bind(&client::handle_read, this,
               boost::asio::placeholders::error,
               boost::asio::placeholders::bytes_transferred));
       }
       else if (0 != bytes_transferred)
       {
           std::cout << "Read failed: " << error.message() << ":" 
                     << error.value() <<  "\n";
       }
   }

private:
   boost::asio::ssl::stream socket_;
   boost::asio::streambuf request_;
   char reply_[max_length];
};

Если мы удалим if (0! = Bytes_transferred), мы получим «короткое чтение» :( .

Если мы будем использовать код as-ai, вывод будет примерно таким:

Запрос:

GET / HTTP / 1.0

Cookie: Nama-nama = Vala-vala

Передано байт: 1024

Ответ: HTTP / 1.0 200 ok Content-type: text / html

..... бла-бла-бла ....

Чтение ... Передано байт: 1024

.....бла-бла-бла .... ..... бла-бла-бла ....

Читаю ... Передано байт: 482

..... бла-бла-бла ....

Чтение ...

Байт передано: 0

При этом, если вместо async_read_some мы пишем код, зачем обычный сокет вернет EOF:

boost::asio::async_read(socket_, response_,
    boost::asio::transfer_at_least(1),
    boost::bind(&client::handle_read_content, this,
    boost::asio::placeholders::error));

, тогда для SSL-сокета мы получим 0 в качестве переданных байтов, а затем short_read.

Я знаю, что нет способа обнаружить отключение в случае, если одноранговый узел, для Например, был просто отключен от сети. Но как обнаружить явное отключение чистого однорангового узла от ситуации, когда одноранговый узел просто не отправляет данные в течение некоторого времени, но, возможно, будет это делать чуть позже?

Или, может, я чего-то не понимаю?

WBR, Андрей

Немного addentum: SSL / TLS имеет обозначение для информирования другой стороны о закрытии соединения. Это close_notify alert. Также можно закрыть базовый TCP-сокет.

В общем, мой вопрос: почему в тех же условиях (сокет TCP был явно закрыт) я получаю EOF в случае tcp :: socket и не получаю ничего для boost :: asio :: ssl :: транслировать.

Это ошибка или функция asio?

Еще одно дополнение: По некоторым причинам asio не предоставил мне EOF ни при получении SSL close_notify, ни при закрытии базового TCP-сокета.

Да, я могу обнаружить обрыв соединения по таймауту. Но как я могу обнаружить правильно закрытые SSL-соединения? Получая short_read?

16
задан Sam Miller 2 August 2013 в 18:04
поделиться