Я пишу сетевую библиотеку, которая оборачивает QUdpSocket
:
QAbstractSocket *UdpNetworkStreamer::addConnection()
{
QUdpSocket *udpSocket = new QUdpSocket(this);
udpSocket->bind(connection.port, QUdpSocket::ShareAddress);
bool ret = udpSocket->joinMulticastGroup(QHostAddress(connection.ip));
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::QueuedConnection);
return udpSocket;
}
QUdpSocket
,readyRead
сигнал.readDatagram
когда readyRead
Поднялся.Все работает нормально, когда я использую библиотеку из приложения Qt GUI.
Проблема начинается, когда другой пользователь включает библиотеку, используемую вне приложения Qt GUI.
Он называет addConnection
(который создает сокет и вызывает соединение на readyRead
)
Нить, на которой addConnection
называется не-Qt.
addConnection
кажется, заканчивается успешно, но readyRead
никогда не излучается.
Звонить читать (хотя нет readyRead
был выпущен) приводит к успешному чтению дейтаграммы.
Исправления, которые не работали:
перемещение потока UDP-сокета в поток this->
QUdpSocket *udpSocket = new QUdpSocket();
udpSocket->moveToThread(this->thread());
udpSocket->setParent(this);
Я попытался смоделировать проблему, позвонив: void
MainWindow::on__btnOpenMulticastReceiver_clicked()
{
QFuture<void> future = QtConcurrent::run(this,
&MainWindow::CreateMulticastConnection, testHandle);
}
Это также привело к появлению тех же симптомов, что и у пользователя в моей библиотеке. readyRead
не был выпущен
QSignalSpy
— Я активировал шпиона на readyRead
сигнал; Счетчик оставался нулевым, хотя я мог читать данные прямо из сокета. Шпион дал действительные результаты (то есть, прогрессировал), когда использованный сокет был инициализирован в основном потоке.
readyRead
даже если он не создан в основном потоке графического интерфейса — я не смог найти ни одного примера, который бы работал без графического интерфейса или вне потоков Qt. Я думаю, что вам нужно добавить Q_OBJECT
макрос в начало класса, откуда вам нужно испустить сигнал. Если вы не сделаете этого, механизм прорези сигнала не будет работать должным образом.
Я решил проблему таким образом:
void MainWindow::OpenConnection()
{
QThread *t = new QThread();
t->start();
SocketWrapper *w= new SocketWrapper();
w->moveToThread(t);
w->metaObject()->invokeMethod(w, "CreateSocket", Qt::QueuedConnection);
}
Вы должны позвонить invokeMethod()
с резьбой обертка была movedTo()
после создания сокета, чтобы поток, создающий сокет, имел работающий цикл обработки событий.
В дополнение к этому, CreateSocket()
должен быть слот в SocketWrapper
, что-то вроде того :
class SocketWrapper : public QObject
{
Q_OBJECT
public:
explicit SocketWrapper(QObject *parent = 0);signals:
public slots:
void readyRead();
void CreateSocket();
private:
QUdpSocket *_socket;
};