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