Сигнал, исходящий от сервера сокетов датаграмм UnixDomain, работающего на QThread, никогда не получался

Файлы, которые я создал

Я создал расширенный класс WorkerThread следующим образом:

// https://stackoverflow.com/a/14546167/11073131
#ifndef THREAD_H
#define THREAD_H

#include <QThread>
#include <QDebug>
#include <QString>
#include "ud_ucase.h"

class WorkerThread : public QThread {
  Q_OBJECT
  public:
    void run() {
      struct sockaddr_un svaddr, claddr;
      int sfd, j;
      ssize_t numBytes;
      socklen_t len;
      char buf[BUF_SIZE];

      sfd = socket(AF_UNIX, SOCK_DGRAM, 0);       // Create server socket
      if (sfd == -1)
          qDebug() << "socket";

      // Construct well-known address and bind server socket to it

      if (strlen(SV_SOCK_PATH) > sizeof(svaddr.sun_path) - 1)
          printf("Server socket path too long: %s", SV_SOCK_PATH);

      if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT)
          printf("remove-%s", SV_SOCK_PATH);

      memset(&svaddr, 0, sizeof(struct sockaddr_un));
      svaddr.sun_family = AF_UNIX;
      strncpy(svaddr.sun_path, SV_SOCK_PATH, sizeof(svaddr.sun_path) - 1);

      if (bind(sfd, (struct sockaddr *) &svaddr, sizeof(struct sockaddr_un)) == -1)
          printf("bind");

      // Receive messages, convert to uppercase, and return to client
      while(1) {
          len = sizeof(struct sockaddr_un);
          qDebug() << "before recvfrom";
          emit progressChanged("before recvfrom");     // 1st emit
          numBytes = recvfrom(sfd, buf, BUF_SIZE, 0,
                              (struct sockaddr *) &claddr, &len);

          if (numBytes == -1)
              printf("recvfrom");

          printf("Server received %ld bytes from %s\n", (long) numBytes,
                  claddr.sun_path);

          buf[numBytes] = 0;
          qDebug() << "buf:" << buf;
          emit progressChanged(buf);            // 2nd emit
          qDebug() << "Emit finished";

          // Convert received messages to uppercase
          for (j = 0; j < numBytes; j++)
              buf[j] = toupper((unsigned char) buf[j]);

          // Return back it to client socket
          if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *) &claddr, len) !=
                  numBytes)
              printf("sendto");
      }
/*
      while(1) {
            // ... hard work
            // Now want to notify main thread:
            emit progressChanged("Some info");
      }
*/
    }
  // Define signal:
  signals:
    void progressChanged(QString info);
};
#endif // THREAD_H

Метод QThread вышеуказанного класса создает и запускает run(), который генерирует полученную строку с помощью сигнала UnixDomain datagram socket server, преобразует эту строку в верхний регистр, а затем возвращает в клиентский сокет.

Слот, который получает упомянутый выше сигнал, определяется на progressChanged(QString info) следующим образом:

void MainWindow::onProgressChanged(QString info) {
    // Processing code
    ui->label->setText("Latest info: " + info);
    qDebug() << "Signal received:" << info;
}

void MainWindow::startWorkInAThread() {
    // Create an instance of your woker
    WorkerThread *workerThread = new WorkerThread;
    // Connect our signal and slot
    connect(workerThread, SIGNAL(progressChanged(QString)),
                          SLOT(onProgressChanged(QString)));
    // Setup callback for cleanup when it finishes
    connect(workerThread, SIGNAL(finished()),
            workerThread, SLOT(deleteLater()));
    // Run, Forest, run!
    workerThread->start(); // This invokes WorkerThread::run in a new thread
}

Функция mainwindow.cpp, связывающая сигнал и слот, вызывается в конструкторе MainWindow.

Текущий результат

При запуске этого приложения MainWindow::startWorkInAThread() получает 1st emit со следующим сообщением QDebug:

before recvfrom
Signal received: "before recvfrom"

Затем отправьте сообщение «ахо» от клиента внешнего сокета, сообщение QDebug указывает, что второй излучатель, который излучает сигнал с полученным сообщением с помощью функции recvfrom() сокета, был отправлен, но так и не получен. Также следующий первый выпуск также был отправлен, но так и не получен.

before recvfrom
Signal received: "before recvfrom"
buf: aho
Emit finished
before recvfrom

И клиент сокета получает сообщение, преобразованное в верхний регистр, как и ожидалось.

./ud_ucase_cl aho
Response 1: AHO

Вопрос

Учитывая, что

  • Получен первый эмитт
  • Клиент сокета получил преобразованное сообщение
  • Но после запуска функции сокета Recvfrom() в QThread ни одно отправленное сообщение не получено.

Почему после Recvfrom() в классе Qthread ни одно сообщение не получено? Как я могу это исправить?

Среда

Qt 5.11.3 Малиновый Пи 2B+ Linux raspberrypi 5.10.103-v7+ #1529 SMP Вт, 8 марта 12:21:37 GMT 2022 Armv7l GNU/Linux GCC 8.3.0

connect(workerThread, SIGNAL(progressChanged(QString)), SLOT(onProgressChanged(QString))); - вам не хватает контекста назначения, и поэтому слот выполняется не в том потоке (он же workerThread), что может вызвать у вас проблемы в зависимости от того, что вы делаете в слоте (мы не видим этого, поскольку вы не предоставили его). минимальный компилируемый воспроизводитель). Также используйте синтаксис подключения в стиле pmf.
chehrlic 11.06.2024 17:53

Поменял на connect(workerThread, WorkerThread::progressChanged, this, MainWindow::onProgressChanged);, но результат тот же.

Ueda Takeyuki 12.06.2024 07:51

Я не думаю, что QLocalServer поддерживает сокет датаграмм.

Ueda Takeyuki 12.06.2024 07:52
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Кажется, ваш сокет зависает в ожидании следующего пакета в функции recvfrom, потому что в UDP целостность данных в сокете не гарантируется. Вы можете использовать функцию select(), чтобы проверить готовность программы получить новую порцию данных.

Я добавил select() непосредственно перед Recvfrom(). Но результат не изменился.

Ueda Takeyuki 13.06.2024 09:40

Вы пытались посмотреть, сколько байт в данный момент находится в UDP-буфере?

Andrei Vukolov 13.06.2024 15:50

Я использую буфер размером всего 10 байт.

Ueda Takeyuki 14.06.2024 04:15

Нет, я имею в виду байты, уже полученные во входящем буфере UDP

Andrei Vukolov 16.06.2024 22:09
Ответ принят как подходящий

Мне удалось создать минимальную среду воспроизведения в виде datagramRep, и я обнаружил, что наиболее подозрительным материалом является объект QTimer в mainwindow.cpp, потому что проблема не воспроизводится, когда я не вызываю timer->start(1000) или увеличиваю интервал. до 60000. Вышеуказанный порог может зависеть от устройства. Я подтвердил это на своем RPi 2 Model B.

Кажется странным, почему QTimer с интервалом в 1 секунду блокируется для получения сигнала. Но это может быть так.

Другие вопросы по теме