Виталий Антипов
Виталий АнтиповҚаң. 18, 2021, 2:51 Т.Қ.

Qt: INTERNAL ERROR: failed to install GetMessage hook: 1158

server

Здравствуйте. Вопрос по простенькому серверу на ПК. Устройства-клиенты подключаются к локальной сети, передают данные на сервер. Задача сервера при каждом подключении клиента (раз в минуту) создавать отдельный поток, в нем принимать данные и отправлять в интерфейс. После получения данных подключение и поток должны закрываться. При тестировании через пару дней приложение упало со следующей ошибкой: "Qt: INTERNAL ERROR: failed to install GetMessage hook: 1158, Текущий процесс использовал все системные разрешения по управлению объектами диспетчера окон". Логи показывают, что соединения/потоки закрываются не сразу после приема данных, а через десятки часов. Похоже что слишком много потоков создано одновременно. Собственно и вопрос к гуру, почему не закрываются потоки сразу, как это можно реализовать? (впервые работаю с сервером и потоками).

main.cpp
#include "mainwindow.h"
#include "myserver.h"
#include <QApplication>
#include <QDir>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyServer server;
    server.startServer();
    MainWindow w;
    QObject::connect(&server, SIGNAL(signal1(qreal)), &w, SLOT(onAppendData(qreal)));
    w.show();
    return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtCharts>
#include <QChartView>
#include <QChart>
#include <QDateTime>
#include <QDebug>

using namespace QtCharts;

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    QLineSeries *series = new QLineSeries();
    QDateTimeAxis *axisX = new QDateTimeAxis;
    QValueAxis *axisY = new QValueAxis();
    int i = 0;
    QDateTime minX;
    QDateTime maxX;
    qreal minY;
    qreal maxY;

public slots:
    void onAppendData(qreal);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QWidget *widget = new QWidget;
    setCentralWidget(widget);
    QVBoxLayout *layout = new QVBoxLayout;
    layout->setMargin(5);
    widget->setLayout(layout);
    QChartView *chartView = new QChartView(this);
    layout->addWidget(chartView);

    QChart *chart = new QChart();
    chart->addSeries(series);
    chart->setTitle("График температуры во времени");

    axisX->setFormat("hh:mm:ss");
    axisX->setTitleText("Время");
    axisX->setTickCount(10);
    chart->addAxis(axisX, Qt::AlignBottom);
    series->attachAxis(axisX);

    axisY->setTitleText("Температура, °С");
    axisY->setLabelFormat("%g");
    axisY->setTickCount(10);
    chart->addAxis(axisY, Qt::AlignLeft);
    series->attachAxis(axisY);
    chartView->setChart(chart);
}

MainWindow::~MainWindow()
{
}

void MainWindow::onAppendData(qreal data)
{
    QDateTime x = QDateTime::currentDateTime();
    qreal y = data;
    if(i == 0){
        minX = x;
        maxX = x;
        minY = y;
        maxY = y;
        axisX->setRange(minX, maxX);
        axisY->setRange(minY, maxY);
        series->append(x.toMSecsSinceEpoch(), y);
    } else {
    minX = axisX->min();
    maxX = axisX->max();
    minY = axisY->min();
    maxY = axisY->max();
    axisX->setRange(x < minX ? x : minX, x > maxX ? x : maxX);
    axisY->setRange(y < minY ? y : minY, y > maxY ? y : maxY);
    if(i>99999){
        series->remove(0);
        minX = QDateTime::fromMSecsSinceEpoch(series->at(0).x());
        axisX->setRange(minX, x > maxX ? x : maxX);
    }
    series->append(x.toMSecsSinceEpoch(), y);
    }
    i++;
}
myserver.h
#ifndef MYSERVER_H
#define MYSERVER_H

#include <QTcpServer>
#include "mythread.h"

class MyServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit MyServer(QObject *parent = 0);
    void startServer();
signals:
    void signal1(qreal);


public slots:
void onSignalData(qreal);
protected:
    void incomingConnection(qintptr socketDescriptor);

};

#endif // MYSERVER_H

myserver.cpp
#include "myserver.h"

MyServer::MyServer(QObject *parent) :
    QTcpServer(parent)
{
}

void MyServer::startServer()
{
    int port = 5555;
    if(!this->listen(QHostAddress("192.168.1.201"),port))
    {
        qDebug() << "Could not start server";
    }
    else
    {
        qDebug() << "Listening to port " << port << "...";
    }

}

void MyServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << socketDescriptor << " Connecting...";
    MyThread *thread = new MyThread(socketDescriptor, this);
    connect(thread, SIGNAL(signalData(qreal)), this, SLOT(onSignalData(qreal)), Qt::DirectConnection);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

void MyServer::onSignalData(qreal data){
    qDebug()<<"слот сработал"<<data;
    emit signal1(data);
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QTcpSocket>
#include <QDebug>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(qintptr ID, QObject *parent = 0);

    void run();

signals:
    void error(QTcpSocket::SocketError socketerror);
    void signalData(qreal);

public slots:
    void readyRead();
    void disconnected();

private:
    QTcpSocket *socket;
    qintptr socketDescriptor;
};

#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"

MyThread::MyThread(qintptr ID, QObject *parent) :
    QThread(parent)
{
    this->socketDescriptor = ID;
}

void MyThread::run()
{
    qDebug() << " Thread started";
    socket = new QTcpSocket();
    if(!socket->setSocketDescriptor(this->socketDescriptor))
    {
        emit error(socket->error());
        return;
    }
    connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
    connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
    qDebug() << socketDescriptor << " Client connected";
    exec();
}

void MyThread::readyRead()
{
    QByteArray Data = socket->readAll();
    qDebug() << socketDescriptor << " Data in: " << Data;
    emit signalData(Data.toFloat());
}

void MyThread::disconnected()
{
    qDebug() << socketDescriptor << " Disconnected";
    socket->deleteLater();
    exit(0);
}
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

7
Алексей Внуков
  • Қаң. 19, 2021, 11:16 Т.Ж.

добрый. давайте начнем с того что у вас выпонено в реализации которую сам Qt даже не рекомендует на данный момент.
1. новый синтаксис сигналов и слотов
2. переопределять run() и наследовать от QThread - не верно, делаем рабочий класс. делаем ему мувтосред и потом старт потока
3. создание сервера и его обвязка - можно вынести в класс интерфейса, и я бы серверу выделил отдельный поток от интерфейса, и потом уже в потоке работа с сокетами
теперь о deleteLater() - оманда выполнется только тогда когда в данном сокете ничего уже происходить не будет, возможно есть какое-то обращение к данному сокету, из-за чего он долго не удаляется. если вам не нужен постоянный конект к серверу, со стороны клиента делайте конект->отправка данных->подтверждение о получении данных->дисконект

    Алексей, спасибо за ответ.
    1. Этот синтаксис сигнал/слот вроде старый и во всех туториалах, про Qt не рекомендует где-то пропустил. Каким образом тогда общаться между потоками?
    2. Спасибо за совет, буду пробовать.
    3. Клиентом является esp8266, которая отдав данные уходит в глубокий сон разрывая соединение. В сокете ничего не происходит, но почему-то deleteLater() не срабатывает сразу, в чем и загвоздка.
    Буду думать/пробовать, спасибо еще раз.

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

        Алексей Внуков
        • Қаң. 20, 2021, 7:49 Т.Ж.
        • (өңделген)
        • Жауап шешім ретінде белгіленді.

        по поводу п.3. Ситуация может быть в том что esp8266 не корректно закрывает соединение. Это проблема всех соединений TCP, если от устройства не пришел корректный сигнал дисконекта то сервер будет держать поток до последнего. только где-то там может произойти событие дисконекта после чего произойдет разрыв и сработает deleteLater(). В таком случае могу посоветовать через какое-то время отправить любой запрос (можно даже пустой) на клиет, и, поскольку клиент со своей стороны уже отрубил соединение и пошел спать, серверу сразу прийдет событие что нет соединения, произойдет дисконект и выполнится deleteLater().

          Огромное спасибо! Про некорректное закрытие соединения со стороны клиента даже не подумал, скорее всего и вправду в этом проблема, надо разбираться с esp8266. За ссылку отдельное спасибо.

            Алексей Внуков
            • Қаң. 20, 2021, 7:57 Т.Ж.

            и еще одно, поскольку, по факту, каждое TCP-соединение это отдельный поток, подумайте о целесообразности дополнительно делать новые потоки

              ESP8266 и вправду не корректно закрывало соединение. Причина оказалась банальной: перед функцией ухода в глубокий сон ESP.deepSleep(60e6) необходимо было поставить небольшую задержку delay(1). Ваше предположение оказалось верным.

                Пікірлер

                Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
                Кіріңіз немесе Тіркеліңіз
                Г

                C++ - Тест 001. Первая программа и типы данных

                • Нәтиже:66ұпай,
                • Бағалау ұпайлары-1
                t

                C++ - Тест 001. Первая программа и типы данных

                • Нәтиже:33ұпай,
                • Бағалау ұпайлары-10
                t

                Qt - Тест 001. Сигналы и слоты

                • Нәтиже:52ұпай,
                • Бағалау ұпайлары-4
                Соңғы пікірлер
                G
                GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
                Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
                d
                dblas5Шілде 5, 2024, 11:02 Т.Ж.
                QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                k
                kmssrАқп. 8, 2024, 6:43 Т.Қ.
                Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                АК
                Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
                Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                Енді форумда талқылаңыз
                Evgenii Legotckoi
                Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
                добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                F
                FynjyШілде 22, 2024, 4:15 Т.Ж.
                при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
                BlinCT
                BlinCTМаусым 25, 2024, 1 Т.Ж.
                Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
                BlinCT
                BlinCTМамыр 5, 2024, 5:46 Т.Ж.
                Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
                Evgenii Legotckoi
                Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
                Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

                Бізді әлеуметтік желілерде бақылаңыз