Russian Qt Forum

Qt => Работа с сетью => Тема начата: texnik от Октябрь 08, 2010, 12:05



Название: Опрос большого числа абонентов по TCP
Отправлено: texnik от Октябрь 08, 2010, 12:05
Здравствуйте все.
Проблема следующая. Есть приложение, которое должно периодически опрашивать большое количество абонентов по протоколу TCP, т.е высылать им некие запросы и получать на них ответы. Для каждого абонента набор запросов различный.

Сейчас я делаю это так. Формируется пул потоков, каждый из которых обрабатывает одно соединение с абонентом и работу с ним. Сами пакеты формируются отдельно и передаются для отсылки через очередь запросов, полученные пакеты закладываются в очередь ответов и обрабатываются тоже отдельно.

Поток вида
tcpclientyhread.h
Код:
#include <QHostAddress>
#include <QTcpSocket>

class TcpClientThread : public QThread
{
    Q_OBJECT
public:
    TcpClientThread();

    void run();

};
tcpclientthread.cpp
Код:
#include "tcpclientthread.h"

TcpClientThread::TcpClientThread() : QThread()
{
}

void TcpClientThread::run()
{    
    QTcpSocket socket;

    socket.connectToHost(ip,port);
    if (socket.waitForConnected(3000))
    {        
        QByteArray outBlock;
        //здесь забираю пакет из очереди запросов
        socket.write(outBlock);

        if (socket.waitForReadyRead(3000))
        {
              QByteArray inBlock = socket.readAll();    
              //выкидываю его во внешнюю очередь ответов              
              socket.disconnectFromHost();                    
              if (socket.state() != QAbstractSocket::UnconnectedState)
              {
                   socket.waitForDisconnected(100);
              }
       }
       else
       {
            //обработка ситуации ошибки ожидания ответа
            socket.disconnectFromHost();
            if (socket.state() != QAbstractSocket::UnconnectedState)
            {
               socket.waitForDisconnected(100);                    
            }
        }
    }
    else
    {
        //обработка ситуации ошибки ожидания подключения
    }
    socket.close();
}

Возникает проблема, когда открывается множество соединений TCP, имеющих состояние TIME_WAIT (netstat), для закрытия которых требуется значительное в рамках интенсивности опроса время. А затем весь опрос "умирает". Полный цикл опроса всех абонентов должен производится хотя в рамках 10 секунд.

Создавать отдельное соединение на каждый абонент не могу из-за количества абонентов, превышающего лимит по соединениям.

Нужен ваш совет. Заранее спасибо.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: vunder от Октябрь 08, 2010, 13:29
Думаю, все-таки нужно создавать несколько соединений, но не все количество абонентов, а пачками, скажем по 10 штук. Это обычная практика. Сканеры портов, например, именно так и делают: задается максимальное количество потоков, если в очереди есть необработанные клиенты, то проверяется, можно ли создать для него новый поток. Если можно, то поток создается. При завершении работа одного из потока снова проверяется, если ли в очереди клиенты.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: texnik от Октябрь 08, 2010, 14:09
Дело в том, что опросить за период нужно все абоненты, и этот период меньше чем период ожидания для удаления соединения операционной системой.
А если я установлю допустим 10 постоянных соединений, то это будет только 10 абонентов.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: vunder от Октябрь 08, 2010, 19:53
Смысл в том, что после обслуживания очередного абонента можно перейти к опросу очередного. Так мы получем несколько потоков для опроса большого числа клиентов


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: texnik от Октябрь 09, 2010, 12:16
Смысл в том, что после обслуживания очередного абонента можно перейти к опросу очередного. Так мы получем несколько потоков для опроса большого числа клиентов
Ну вообще то  я так и делаю. Проблема не в создании множества потоков (пул потоков ограничен), а в том, что после того как производится disconnectFromHost текущее TCP соединение висит в состоянии TIME_WAIT еще более минуты и через некоторое время таких соединений становится слишком много.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: SABROG от Октябрь 09, 2010, 21:18
Проблема не в создании множества потоков (пул потоков ограничен), а в том, что после того как производится disconnectFromHost текущее TCP соединение висит в состоянии TIME_WAIT еще более минуты и через некоторое время таких соединений становится слишком много.
Насколько я знаю это стандартное поведение протокола TCP/IP и относится ко всем программам, после закрытия сокета он остается открытым какое-то время для операционной системы, чтобы гарантировать доставку пакетов с информацией о завершении соединения. Qt тут не при чем.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: texnik от Октябрь 10, 2010, 01:55
Может подскажете в какую сторону "курить"?)


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: SABROG от Октябрь 10, 2010, 10:22
превышающего лимит по соединениям
А как это выглядит? Вы опросили 1000 абонентов, закрыли все соединения и пытаетесь заново их опросить, а ОС не дает, так как закрытые сокеты остались открытыми где-то внутри ОС и висят с флагом TIME_WAIT?

Создавать отдельное соединение на каждый абонент не могу из-за количества абонентов, превышающего лимит по соединениям.
Тут я не понял. А как можно не создавать отдельное соединение/сокет на каждого клиента? Broadcasting, который дальше шлюза не уйдет?


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: texnik от Октябрь 10, 2010, 19:56
А как это выглядит? Вы опросили 1000 абонентов, закрыли все соединения и пытаетесь заново их опросить, а ОС не дает, так как закрытые сокеты остались открытыми где-то внутри ОС и висят с флагом TIME_WAIT?
Именно так и выглядит, при опросе для каждого нового абонента создается соединение, производится обмен, потом соединение закрывается. После закрытия соединения сокеты висят с флагом TIME_WAIT некоторое время.

Цитировать
Тут я не понял. А как можно не создавать отдельное соединение/сокет на каждого клиента? Broadcasting, который дальше шлюза не уйдет?
Здесь вероятно я не правильно выразился - я имел в виду то, что возможное количество абонентов значительно больше количества сокетов в ОС и нельзя создать постоянное соединения для каждого абонента. Получается что надо работать с абонентами последовательно, высвобождая сокеты.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: SABROG от Октябрь 10, 2010, 22:00
Получается что надо работать с абонентами последовательно, высвобождая сокеты.
Это понятно. Непонятно в чем проблема. Просто хочется, чтобы не висели в netstat или всё-таки ОС не дает после определенного количества попыток снова соединяться и программа перестает корректно работать?


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: texnik от Октябрь 11, 2010, 11:52
Получается что ОС не дает соединяться снова - соответственно и программа перестает корректно работать. Больше не происходит подключения.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: SABROG от Октябрь 11, 2010, 12:23
Получается что ОС не дает соединяться снова - соответственно и программа перестает корректно работать. Больше не происходит подключения.

Это известная (http://technet.microsoft.com/ru-ru/magazine/2007.12.network.aspx) проблема p2p клиентов. Для устранения патчат файлик tcpip.sys, чтобы уменьшить время освобождения сокетов протоколом. Другой вариант поставить минимальную задержку перед следующим сканированием одного и того же IP адреса в 300 секунд.


Название: Re: Опрос большого числа абонентов по TCP
Отправлено: texnik от Октябрь 11, 2010, 13:12
Все ясно. Большое спасибо.