Russian Qt Forum
Ноябрь 22, 2024, 15:19 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Сканирование портов в QThreadPool  (Прочитано 8495 раз)
Павелъ
Гость
« : Декабрь 13, 2017, 17:16 »

Доброго времени суток.

Требуется узнать открытые на устройстве tcp-порты.

Решил делать эту задачу через QTCPSocket.

В main.cpp выделил пул потоков на 600 потоков.

Код:
QThreadPool::globalInstance()->setMaxThreadCount(600);

Но, 600 потоков - для всего приложения в целом. А для задачи сканирования решил использовать 300 потоков.

Реализация функции сканирования:

Код:
bool CommonFunctions::isPortListen(int port, QString ipAddress, int msecs)
{
    QTcpSocket sock;
    sock.connectToHost(QHostAddress(ipAddress),port);
    if(sock.waitForConnected(msecs))
    {
        sock.close();
        return true;
    }
    return false;
}

Ожидание ответа на прослушивание я решил использовать 10 миллисекунд.

Арифметика:

У нас есть 65536 [0:65535] возможных портов.

Время отклика 10 миллисекунд.

То-есть, при сканировании в одном потоке у нас должно затратиться на всё про всё максимум 65536 * 10 = 655360 миллисекунд.
Если сканирование распараллелить на 300 потоков, то время сканирование уменьшается в 300 раз, то есть 655360 / 300 = 2184,5 миллисекунд.
Делим полученное значение на 1000 и получаем количество затраченных секунд на сканирование примерно 2,2.

Но, по факту получается, что время затрачивается в разы больше, как будто и не было распараллеливание, так ещё и интерфейс висит во время сканирования.

Вот, собственно потомок от QRunnable, в котором происходит сканирование:

Код:
#ifndef LISTENPORT_H
#define LISTENPORT_H

#include "commonfunctions.h"

#include <QObject>
#include <QRunnable>

class ListenPort : public QObject, public QRunnable
{
    Q_OBJECT
public:
    explicit ListenPort(QString ipAddress, int port, int msecs, QObject *parent = 0);
private:
    QString _ipAddress;
    int _port;
    int _msecs;

    void run();

signals:
    void portIsListen(QString ipAddress, int port);

    void stopped();

public slots:
};

#endif // LISTENPORT_H

Код:
#include "listenport.h"

ListenPort::ListenPort(QString ipAddress, int port, int msecs, QObject *parent) :
    QObject(parent),
    _ipAddress(ipAddress),
    _port(port),
    _msecs(msecs)
{    
}

void ListenPort::run()
{
    if(CommonFunctions::isPortListen(_port,_ipAddress,_msecs))
    {
        emit portIsListen(_ipAddress,_port);
    }

    if(_port == 65535)
    {
        emit stopped();
    }
}


Ну, и сам запуск:

Код:
void IpStandardItem::startPortScan()
{
    
    
    QThreadPool *pool = new QThreadPool();
    
    for(int i=0;i<=65535;i++)
    {
        
        ListenPort *lisP = new ListenPort(_ipInformation.IpAddress,i,10);
        
        connect(lisP,&ListenPort::portIsListen,[=](QString, int port){
            
            emit canInsertPort(port);
        });
        
        
        
        
        pool->start(lisP);
        
        
    }
    
    
}


Здесь, правда, не написано, сколько потоков я выделяю на созданный мною пул.
Но, даже, если я делаю pool->setMaxThreadCount(300) - это не даёт результата.


Что я опять не так наговнокодил?
« Последнее редактирование: Декабрь 13, 2017, 17:24 от Павелъ » Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #1 : Декабрь 13, 2017, 19:55 »

Что я опять не так наговнокодил?

забавный расчет времени, драйвера и сетевое оборудование только не в курсе )

и ты видимо не знаком с  nmap, прочитай его документацию и просто его вызови - все уже сделано за нас


Записан
Павелъ
Гость
« Ответ #2 : Декабрь 13, 2017, 21:22 »

Что я опять не так наговнокодил?


и ты видимо не знаком с  nmap, прочитай его документацию и просто его вызови - все уже сделано за нас




знаком. Только начальник запретил его использовать.
Всё надо писать самому.
Записан
Павелъ
Гость
« Ответ #3 : Декабрь 13, 2017, 21:24 »

Если у меня waite 10 миллисекунд, то как сетевое оборудование может повлиять на продолжительность?

Либо я получу отклик менее, чем за 10 миллисекунд, либо - не получу, что в моём случае будет означать, что порт закрыт.

Разве нет?
Записан
zhbr
Гость
« Ответ #4 : Декабрь 14, 2017, 07:10 »

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

кстати а какой процессор у тебя?
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #5 : Декабрь 14, 2017, 08:35 »

знаком. Только начальник запретил его использовать.
Всё надо писать самому.

и чем он это мотивировал ?
странно что он разрешил qt использовать
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #6 : Декабрь 14, 2017, 08:48 »

Если у меня waite 10 миллисекунд, то как сетевое оборудование может повлиять на продолжительность?
Либо я получу отклик менее, чем за 10 миллисекунд, либо - не получу, что в моём случае будет означать, что порт закрыт.
Разве нет?

в случаи одного адреса и порта примерно так и есть
но когда много - нужно смотреть как это делается конкретной реализацией внутри qt, очереди сокеты и т.п.
могут быть ограничения ОС на одновременное установление соединений, сокетов, открытых файлов и т.п.
можешь сравнить код qt и код nmap, а также их трафик
поэтому _глупо_ переписывать nmap не разбираясь во всех тонкостях tcp/ip и ос
ну если нечем заняться - то конечно можно, исследование вообще интересное занятие

Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #7 : Декабрь 14, 2017, 12:16 »

Кроме того, если быстро сканить, то фаерфол удаленного узла просто может заигнорить тебя и ничо не даст "отсканить" (ЕМНИП). Тут нужно с умом подходить (взять NMAP и не мучаться, он же вроде минимум на трех лицензиях GPL, LGPL, BSD - чего бояться то?).

Да и потоков многовато.. достаточно по числу ядер + 1, например. А можно вообще без потоков, а создать 100500 сокетов (ну, или штук по 10 сразу) и сразу шмяк - и всем делать коннект к разным портам, благо что коннект асинхронный.. (но тут можно на бан нарваться Улыбающийся )
« Последнее редактирование: Декабрь 14, 2017, 12:22 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #8 : Декабрь 14, 2017, 12:31 »

Тут нужно с умом подходить (взять NMAP и не мучаться, он же вроде минимум на трех лицензиях GPL, LGPL, BSD - чего бояться то?).

лицензия никак не влияет на использование если nmap не встраивать в программу, а вызвать через qprocess и распарсить вывод

но хотелось бы услышать от ТС причину запрета использования nmap от его начальника

Записан
Павелъ
Гость
« Ответ #9 : Декабрь 14, 2017, 12:46 »

Тут нужно с умом подходить (взять NMAP и не мучаться, он же вроде минимум на трех лицензиях GPL, LGPL, BSD - чего бояться то?).

лицензия никак не влияет на использование если nmap не встраивать в программу, а вызвать через qprocess и распарсить вывод

но хотелось бы услышать от ТС причину запрета использования nmap от его начальника



Гос. Предприятие. Могут к придраться к лицензии. Могут что-нибудь про сертификацию сказать. Весь функционал nmap всё равно не нужен. Писали звёздно-полосатые. Может на совещании какой-нибудь умный профессор сказать, что не всё гуд. Просто сказал начальник, спорить не буду. Разговоров много про свободное по и отечественное. По факту только разговоры. Как писали для Виндовс, так и будем писать. Как делали документы в ворде, так и будем ещё 50 лет делать. Вот и все причины.
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #10 : Декабрь 14, 2017, 15:31 »

а я бы поспорил с начальником и профессором, все же надо думать головой
nmap "сертифицирован" в рамках наших ОС типа МСВС или Астры
про то, кто писал софт вообще смешно ибо опенсорс

Записан
Павелъ
Гость
« Ответ #11 : Декабрь 14, 2017, 22:41 »

Если у меня waite 10 миллисекунд, то как сетевое оборудование может повлиять на продолжительность?
Либо я получу отклик менее, чем за 10 миллисекунд, либо - не получу, что в моём случае будет означать, что порт закрыт.
Разве нет?

в случаи одного адреса и порта примерно так и есть
но когда много - нужно смотреть как это делается конкретной реализацией внутри qt, очереди сокеты и т.п.
могут быть ограничения ОС на одновременное установление соединений, сокетов, открытых файлов и т.п.
можешь сравнить код qt и код nmap, а также их трафик
поэтому _глупо_ переписывать nmap не разбираясь во всех тонкостях tcp/ip и ос
ну если нечем заняться - то конечно можно, исследование вообще интересное занятие




nmap жрёт мало трафика и быстро выдаёт порты.

У меня вопрос по поводу того, как сделать одновременную реализацию сокетов.

функция

Код:
void MainWindow::recursivePortScan(QString ipAddress, int port)
{

    qDebug() << port;

    if(ports_count > 65535)
    {
        qDebug() << "scanned all";
        return;
    }

    tek_ports_count++;

    QTcpSocket *sock = new QTcpSocket();


    connect(sock,&QTcpSocket::stateChanged,[=](QAbstractSocket::SocketState test){
        if(test == QAbstractSocket::ConnectedState)
        {
            qDebug() << port;
            sock->disconnectFromHost();
        }
        else if(test == QAbstractSocket::UnconnectedState)
        {
            sock->close();
        }
    });


    connect(sock,&QTcpSocket::disconnected,[=](){
        sock->close();
    });

    connect(sock,&QTcpSocket::aboutToClose,[=](){
        sock->blockSignals(true);
        sock->deleteLater();

        ports_count++;
        tek_ports_count--;

        if(tek_ports_count <= 5000)
        {
            recursivePortScan(ipAddress,ports_count + 5001);//вызываем рекурсивно, освободилось место для сканирования
        }
    });

    sock->connectToHost(QHostAddress(ipAddress),port);
}



вызов

Код:
    tek_ports_count = 0;

    ports_count = 0;


    for(int i=0;i<=65535/*5000*/;i++)
    {
        recursivePortScan("192.168.56.254", i);

    }


Когда я в цикле вызываю 5 тысяч раз функцию, то есть создаю сокеты и пишу реализацию по сигналам, то довольно быстро сканируются порты, причём открытые - моментально. Дальше идёт более медленное сканирование закрытых.

Когда я в цикле создаю 6536 сокетов, то программа лагает и выдаёт ошибки:

Код:
QEventDispatcherWin32::registerTimer: Failed to create a timer (Текущий процесс использовал все системные разрешения по управлению объектами диспетчера окон.)

Я специально замутил рекурсию с той логикой, что сначала создаётся около 5000 сокетов, но они постепенно закрываются, и на их место должны приходить новые, и так до 65535.
Но, трафик резко возрастает на 5000 первых, а дальше падает. И сканирование идёт очень долго.

У меня появилась идея замутить с таймером. Раз уж моментально сканируются открытые порты, то можно по 5000 портов сканировать и прекращать после определённого промежутка остальные.

Такой подход имеет место быть?

И даже при относительно быстром сканировании при создании около 5000 сокетов трафик не растёт выше 2,5 мега/бита. Хотя заливка файла на самбу занимает 100 мега/бит.
Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #12 : Декабрь 15, 2017, 00:01 »

я полагаю, что для задачи быстрого сканирования нужно использовать сырые сокеты на уровне api
с QTcpSocket тоже можно, но будет медленнее
чтото сказать конкретнее сложно без рабочего минимального примера и более плотного разбора с ним
Записан
zhbr
Гость
« Ответ #13 : Декабрь 15, 2017, 06:33 »

я полагаю, что для задачи быстрого сканирования нужно использовать сырые сокеты на уровне api
и мультиплексирование
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.057 секунд. Запросов: 23.