Как обнаружить, когда разъём tcp boost отключается
Предположим, что у меня есть сокет:
std::shared_ptr<tcp::socket> socket( new tcp::socket(acceptor.get_io_service()) );
acceptor.async_accept( *socket, std::bind( handleAccept, this, std::placeholders::_1, socket, std::ref(acceptor)) );
И я храню weak_ptr в указанном сокете в контейнере. Мне нужно это, потому что я хочу разрешить клиентам запрашивать список других клиентов, чтобы они могли отправлять сообщения друг другу.
clients_.insert(socket); // pseudocode
Затем я запускаю несколько асинхронных операций
socket->async_receive( boost::asio::buffer(&(*header), sizeof(Header))
, 0
, std::bind(handleReceiveHeader, this, std::placeholders::_1, std::placeholders::_2, header, socket));
Как определить, когда соединение закрыто, поэтому я могу удалить мой сокет из контейнера?
clients_.erase(socket); // pseudocode
Ответы
Ответ 1
Отключение сокета TCP обычно сигнализируется в asio
с помощью eof
или connection_reset
. Например.
void async_receive(boost::system::error_code const& error,
size_t bytes_transferred)
{
if ((boost::asio::error::eof == error) ||
(boost::asio::error::connection_reset == error))
{
// handle the disconnect.
}
else
{
// read the data
}
}
Я использую boost::signals2
для сообщения об отключении, хотя вы всегда можете передать указатель на функцию в свой класс сокетов и затем вызвать это.
Будьте осторожны с временем жизни вашего сокета и обратного вызова, см. boost-async-functions-and-shared-ptrs
Ответ 2
Есть много вариантов, некоторые из них:
-
Когда вы храните weak_ptr
в контейнере, это не продлит срок службы сокета, поэтому, когда ваш обработчик получит boost::asio::error::eof
(или что-то еще), он не будет копировать/перемещать shared_ptr
, и сокет будет удален (если у вас нет других shared_ptr
). Итак, вы можете сделать что-то вроде: if(socket.expired()) clients_.erase(socket);
-
Проверьте код ошибки в вашем обработчике - он укажет, когда соединение закрыто. Используя эту информацию - вы можете вызывать clients_.erase
из самого обработчика.
Не могли бы вы привести пример # 2?
Это будет что-то вроде:
socket->async_receive
(
boost::asio::buffer(&(*header), sizeof(Header)), 0,
[=, &clients_](const system::error_code& error, size_t bytes_transferred)
{
if(error) // or some specific code
{
clients_.erase(socket); // pseudocode
}
else
{
// continue, launch new operation, etc
}
}
);