Виталий Антипов
Виталий АнтиповҚаң. 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). Ваше предположение оказалось верным.

                Пікірлер

                Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
                Кіріңіз немесе Тіркеліңіз
                OI
                • Ora Iro
                • Жел. 24, 2024, 5:38 Т.Қ.

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

                • Нәтиже:40ұпай,
                • Бағалау ұпайлары-8
                AD

                C++ - Тест 004. Указатели, Массивы и Циклы

                • Нәтиже:50ұпай,
                • Бағалау ұпайлары-4
                m
                • molni99
                • Қаз. 26, 2024, 11:37 Т.Ж.

                C++ - Тест 004. Указатели, Массивы и Циклы

                • Нәтиже:80ұпай,
                • Бағалау ұпайлары4
                Соңғы пікірлер
                ИМ
                Игорь МаксимовҚар. 22, 2024, 10:51 Т.Қ.
                Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                Evgenii Legotckoi
                Evgenii LegotckoiҚар. 1, 2024, 12:37 Т.Ж.
                Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                A
                ALO1ZEҚаз. 19, 2024, 6:19 Т.Қ.
                Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                ИМ
                Игорь МаксимовҚаз. 5, 2024, 5:51 Т.Қ.
                Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                d
                dblas5Шілде 5, 2024, 9:02 Т.Қ.
                QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                Енді форумда талқылаңыз
                Evgenii Legotckoi
                Evgenii LegotckoiМаусым 25, 2024, 1:11 Т.Ж.
                добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                t
                tonypeachey1Қар. 15, 2024, 5:04 Т.Қ.
                google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
                NSProject
                NSProjectМаусым 4, 2022, 1:49 Т.Қ.
                Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
                9
                9AnonimҚаз. 25, 2024, 7:10 Т.Қ.
                Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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