我在QTcpSockets和線程結合方面遇到了一些麻煩。如何使用線程Qt網絡中的信號和插槽?
我想我誤解了關於線程的文檔,也許你可以解釋我的錯誤在哪裏。什麼部分應該進入run()方法,並且當一個信號被髮送並連接到線程類中的一個插槽時,它會在哪裏接收?在「基地」,而不是在運行(),對不對?那麼,我如何通知「正在運行」的部分,它有什麼必須做的?共享對象?怎麼樣?
我想到底存檔如下:
+-----------------------+
| Server |
| keeps some global |
| objects |
+--X----------------X---+
X X
+---------------X---+ +--X----------------+
| | | |
| Thread for Client | | Thread for Client |
| B | | A |
| keeps local data | | keeps local data |
+-----------X-------+ +-----------X-------+
X X
X X
+---------X----+ +--------X-----+
| Socket | | Socket |
+-------+---+--+ +----+---+-----+
^ | | ^
| | ---------------- | |
| | Network | |
| | --------------- | |
| | | | +----------------+
| | | | | |
| | | +-------+ Client A |
| | | | |
| | +---------->+----------------+
| |
| | +----------------+
| +------------------------------------->+ |
| | Client B |
+------------------------------------------+ |
+----------------+
下面添加代碼的工作賦予「在QSocketNotifier:插座通知者不能啓動或從另一個線程禁用」。我以前的方法(這裏沒有代碼)給了「QObject:不能爲不同的線程中的父項創建子項」。我也讀過Events-Threads-Objects wiki文章(https://wiki.qt.io/Threads_Events_QObjects),但我想我有些東西混淆了。
我在這裏需要做些什麼改變,客戶端A可以發送數據到服務器,服務器更改數據並將答案傳遞給客戶端A和B(我將設置保持活動選項到實際的套接字應用程序,但出於簡化原因將其留在此處)。所有「客戶端」(他們的線程)必須能夠從服務器讀取和修改對象。這樣做的最佳方法是什麼?我想我應該在這裏使用信號和插槽,並且自動連接應該足夠好(如果所有線程都被通知一次發送數據,我可以,我的協議中有一個接收者ID,所以我可以檢查消息是否應該是調用write()之前丟棄
server.pro:
QT += network
QT += core
HEADERS = \
server.h \
clientthread.h
SOURCES = \
main.cpp \
server.cpp \
clientthread.cpp
clietthead.h:
#ifndef CTHREAD_H
#define CHREAD_H
#include <QThread>
#include <QTcpSocket>
class ClientThread : public QThread {
Q_OBJECT
public:
ClientThread(int socketDescriptor, QObject *parent);
void run() Q_DECL_OVERRIDE;
QTcpSocket * tcpSocket;
public slots:
void slot_msg_answer();
void slot_request_msg_FromServer();
signals:
void error(QTcpSocket::SocketError socketError);
void signal_for_Server_request_msg();
private:
int socketDescriptor;
};
#endif
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QTcpServer>
class Server : public QTcpServer {
Q_OBJECT
signals:
void signalFor_PT_msg_answert(QString);
public:
Server(QObject *parent = 0);
public slots:
void slot_request_msg();
protected:
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
private:
};
#endif
clientthread.cpp
#include "clientthread.h"
#include <QTcpSocket>
#include <QtNetwork>
ClientThread::ClientThread(int socketDescriptor, QObject *parent)
: QThread(parent), socketDescriptor(socketDescriptor) {
}
void ClientThread::slot_request_msg_FromServer() {
emit signal_for_Server_request_msg();
}
void ClientThread::run() {
tcpSocket = new QTcpSocket();
tcpSocket->setSocketOption(QAbstractSocket::KeepAliveOption, true);
if (!tcpSocket->setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket->error());
return;
}
QByteArray ba ("foo");
tcpSocket->write(ba);
tcpSocket->flush();
exec();
}
void ClientThread::slot_msg_answer() {
QByteArray ba ("bar");
tcpSocket->write(ba);
tcpSocket->flush();
}
的main.cpp
#include <QtCore>
#include "server.h"
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Server server_;
if (!server_.listen(QHostAddress::Any, 1234)) {
qDebug() << "unable to start the server";
return -1;
}
return app.exec();
}
server.cpp
#include "server.h"
#include "clientthread.h"
#include <QTimer>
Server::Server(QObject *parent) : QTcpServer(parent) {
}
void Server::slot_request_msg() {
emit signalFor_PT_msg_answert("hello");
}
void Server::incomingConnection(qintptr socketDescriptor) {
ClientThread *thread = new ClientThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(this, &Server::signalFor_PT_msg_answert, thread , &ClientThread::slot_msg_answer);
connect(thread, &ClientThread::signal_for_Server_request_msg, this, &Server::slot_request_msg);
thread->start();
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), thread, SLOT(slot_msg_answer()));
timer->start(2000);
}
所有上面的代碼是基於Qt的螺紋時運服務器的例子,這是在BSD授權:
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
你有看過這個嗎? http://doc.qt.io/qt-5/threads-qobject.html特別是帶有事件循環的部分。 – Hayt
是的,我讀過它,並理解它使用「exec();」在「run()」中啓動線程的「本地」事件回調,並且不在「connect(...);」上使用顯式連接類型使qt自己選擇正確的連接(默認:qtautoconnection)。 – user2567875
'QThread'更像是一個線程控制器,所以除非你想改變Qt管理線程的方式,否則你最好不要繼承它。 [本文](https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/)描述了一種很好的方法, QThread'。 – TheDarkKnight