Я создал расширенный класс 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 ни одно сообщение не получено? Как я могу это исправить?
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, WorkerThread::progressChanged, this, MainWindow::onProgressChanged);
, но результат тот же.
Я не думаю, что QLocalServer поддерживает сокет датаграмм.
Кажется, ваш сокет зависает в ожидании следующего пакета в функции recvfrom
, потому что в UDP целостность данных в сокете не гарантируется. Вы можете использовать функцию select(), чтобы проверить готовность программы получить новую порцию данных.
Я добавил select() непосредственно перед Recvfrom(). Но результат не изменился.
Вы пытались посмотреть, сколько байт в данный момент находится в UDP-буфере?
Я использую буфер размером всего 10 байт.
Нет, я имею в виду байты, уже полученные во входящем буфере UDP
Мне удалось создать минимальную среду воспроизведения в виде datagramRep, и я обнаружил, что наиболее подозрительным материалом является объект QTimer в mainwindow.cpp, потому что проблема не воспроизводится, когда я не вызываю timer->start(1000)
или увеличиваю интервал. до 60000. Вышеуказанный порог может зависеть от устройства. Я подтвердил это на своем RPi 2 Model B.
Кажется странным, почему QTimer с интервалом в 1 секунду блокируется для получения сигнала. Но это может быть так.
connect(workerThread, SIGNAL(progressChanged(QString)), SLOT(onProgressChanged(QString)));
- вам не хватает контекста назначения, и поэтому слот выполняется не в том потоке (он же workerThread), что может вызвать у вас проблемы в зависимости от того, что вы делаете в слоте (мы не видим этого, поскольку вы не предоставили его). минимальный компилируемый воспроизводитель). Также используйте синтаксис подключения в стиле pmf.