Название: [Решено] Проблема с сервером, зависшие клиенты Отправлено: Ground от Июль 08, 2012, 07:22 Доброго времени суток!
Появилось у меня два вопроса, на которые без посторонней помощи не могу найти ответа. Итак: 1. Первый вопрос - общий. У меня есть класс на базе QTcpServer. В нем массив клиентских сокетов (QTcpSocket). Так вот, при отключении клиента, я выполняю следующий код: Код Таким образом, я сокет закрываю, и вызываю метод отложенного удаления. Вопрос - можно ли сразу после deleteLater занулять указатель? Утечки не будет? Просто при вызове deleteLater не срабатывает QPointer, и автоматически не зануляет указатель. 2. Второй вопрос - он же основной. При подключении клиента у меня выполняется следующий код: Код Косяк этого кода в том, что клиент может отключиться после вызова nextPendingConnection() и до подключения сигнала disconnected(). В итогу появляется висящий сокет. У меня, конечно, есть функция с таймером, которая прибивает все сокеты в состоянии QAbstractSocket::UnconnectedState, но меня напрягает такая ситуация - из-за нее вылазят некоторые другие баги. Как можно решить такую проблему? Название: Re: Проблема с сервером, зависшие клиенты Отправлено: alexis031182 от Июль 08, 2012, 11:03 1. Можно. Утечки не будет.
2. Update: не увидел скролл для второго листинга Название: Re: Проблема с сервером, зависшие клиенты Отправлено: mutineer от Июль 08, 2012, 12:12 1. Скорее всего QPointer не реагирует потому, что deleteLater() удаляет объект не сразу при вызове
Название: Re: Проблема с сервером, зависшие клиенты Отправлено: Ground от Июль 08, 2012, 12:25 1. Можно. Утечки не будет. Да вот сразу, после nextPendingConnection(). Баг редкий, проявляется только под стресс-тестированием2. А где у Вас конектится disconnected()? Код
1. Скорее всего QPointer не реагирует потому, что deleteLater() удаляет объект не сразу при вызове Ну я вообще рассуждал так, что раз QPointer требует QObject в качестве объекта наблюдения, то они связываются сигналами (иначе зачем QObject нужен?). Ну и соответственно, логично было бы, если бы QPointer висел на сигнале destroyed() от объекта наблюдения. Название: Re: Проблема с сервером, зависшие клиенты Отправлено: alexis031182 от Июль 08, 2012, 12:31 Да вот сразу, после nextPendingConnection(). Баг редкий, проявляется только под стресс-тестированием Тогда может между этими строками просто проверять состояние сокета, и если оно неудовлетворительное, то переходить к удалению сокета. Ещё можно чуть-чуть снизить латентность реакции на появление нового соединения путём перегрузки... Код
Название: Re: Проблема с сервером, зависшие клиенты Отправлено: mutineer от Июль 08, 2012, 12:32 1. Скорее всего QPointer не реагирует потому, что deleteLater() удаляет объект не сразу при вызове Ну я вообще рассуждал так, что раз QPointer требует QObject в качестве объекта наблюдения, то они связываются сигналами (иначе зачем QObject нужен?). Ну и соответственно, логично было бы, если бы QPointer висел на сигнале destroyed() от объекта наблюдения. Название: Re: Проблема с сервером, зависшие клиенты Отправлено: Ground от Июль 08, 2012, 12:58 Логично, да. Только destroyed не испускается непосредственно при вызове deleteLater(), он испускает уже при непосредственном удалении объекта Ну это понятно. Но ведь и от QPointer только и требуется - в ответ на этот сигнал занулить указатель. А у меня получается так, что даже через пол минуты (!) висит неудаленный сокет в состоянии QAbstractSocket::UnconnectedState. Ну главное, что его можно занулить вручную, тогда добрая половина проблем снимается. И еще один момент хотел спросить. Я правильно понимаю, при использовании стандартного QTcpServer, асинхронно идет только отправка данных клиентам, ожидание данных от клиента? Подключение новых клиентов, обработка входящих данных и пр. обрабатываются непосредственно в потоке с QTcpServer? Название: Re: Проблема с сервером, зависшие клиенты Отправлено: alexis031182 от Июль 08, 2012, 13:03 ... Всё, и отправка, и приём данных, и подключение с отключением клиентов выполняется в одном потоке. Асинхронность достигается лишь формированием соответствующих событий.И еще один момент хотел спросить. Я правильно понимаю, при использовании стандартного QTcpServer, асинхронно идет только отправка данных клиентам, ожидание данных от клиента? Подключение новых клиентов, обработка входящих данных и пр. обрабатываются непосредственно в потоке с QTcpServer? Название: Re: Проблема с сервером, зависшие клиенты Отправлено: LisandreL от Июль 08, 2012, 15:11 А у меня получается так, что даже через пол минуты (!) висит неудаленный сокет в состоянии QAbstractSocket::UnconnectedState. Может редко в цикл обработки событий вываливаетесь?Название: Re: Проблема с сервером, зависшие клиенты Отправлено: Igors от Июль 08, 2012, 16:15 Ну я вообще рассуждал так, что раз QPointer требует QObject в качестве объекта наблюдения, то они связываются сигналами (иначе зачем QObject нужен?). Ну и соответственно, логично было бы, если бы QPointer висел на сигнале destroyed() от объекта наблюдения. Нет, сигналами они не связываются. QObject держит хеш всех QPointer указывающих на него. Когда QPointer меняется хеш корректируется. QPointer должен становиться нулевым если сработал деструктор QObject. Зануление ничем технически не грозит, но затемняет картину. Что мешает удалить явно (explicit)?Косяк этого кода в том, что клиент может отключиться после вызова nextPendingConnection() и до подключения сигнала disconnected(). В итогу появляется висящий сокет. Может так: в конце метода Server::slotAcceptClient() проверить состояние и если не гуд, просто удалить сокет, тогда проверка в disconnect сработаетНазвание: Re: Проблема с сервером, зависшие клиенты Отправлено: Ground от Июль 09, 2012, 03:15 Проблема решена, всем спасибо за участие в обсуждении. Львиная доля проблем возникала из-за не зануления QPointer. Часть с зависшими клиентами решилась с помощью:
Код За что спасибо alexis031182. Сегодня еще проверил способ, предложенный Igors. Он тоже работает, решает проблему, и даже проще. Может так: в конце метода Server::slotAcceptClient() проверить состояние и если не гуд, просто удалить сокет, тогда проверка в disconnect сработает Нет, сигналами они не связываются. QObject держит хеш всех QPointer указывающих на него. Когда QPointer меняется хеш корректируется. QPointer должен становиться нулевым если сработал деструктор QObject. Зануление ничем технически не грозит, но затемняет картину. Что мешает удалить явно (explicit)? Если удалять явно (несмотря на принудительный disconnect сигналов), Qt бросает предупреждение об отсутствующем получателе. |