[英]How to create QTcpServer on a QThread and then stop it from the main thread
我在下面提供了我的整個代碼。 請原諒這個設計,因為我是Qt的新手,這是一個快速而骯臟的例子。
我想做的是創建一個管理QTcpServer偵聽器的QThread。 我希望它能夠在停止時關閉監聽器,然后在再次啟動時重新打開它。 請忽略以下事實:偵聽器可能現在正在泄漏,我稍后將解決該問題。
我相信問題在於,當調用Stop時,它將在與創建線程(在TcpServerThread上創建)不同的線程(從主線程調用)上調用m_listener-> close()方法。 所以問題是,我該如何解決? 或者如何重新設計它以避免出現此問題?
這不是完整的設計,我做了一個模仿真實事物的玩具示例。
tcpserverthread.h
#ifndef TCPSERVERTHREAD_H
#define TCPSERVERTHREAD_H
#include <QObject>
#include <QThread>
class QTcpServer;
class TcpServerThread : public QThread
{
Q_OBJECT
public:
TcpServerThread();
void run();
void Start();
void Stop();
public slots:
void newConnection();
private:
QTcpServer* m_pListener;
};
#endif // TCPSERVERTHREAD_H
tcpserverthread.cpp
#include "tcpserverthread.h"
#include "tcpserver.h"
#include <iostream>
#include <QTcpServer>
#include <QTcpSocket>
#include <QCoreApplication>
TcpServerThread::TcpServerThread()
{
}
void TcpServerThread::run()
{
std::cout << "thread started ..." << std::endl;
std::cout << "listener starting ..." << std::endl;
m_pListener = new QTcpServer();
connect(m_pListener, SIGNAL(newConnection()), this, SLOT(newConnection()));
if(!m_pListener->listen(QHostAddress::Any, 1234))
{
std::cout << "listener could NOT START - " << m_pListener->errorString().toStdString() << std::endl;
}
else
{
std::cout << "listener SUCCESSFULLY STARTED" << std::endl;
}
// std::cout << "thread running..." << std::endl;
// m_pListener = new TcpServer();
// m_pListener->Start();
exec();
}
void TcpServerThread::newConnection()
{
qDebug() << "in new conn ... ";
//std::cout << "in new conn.." << std::endl;
QTcpSocket *soc = m_pListener->nextPendingConnection();
soc->write("hello client");
}
void TcpServerThread::Start()
{
start();
}
void TcpServerThread::Stop()
{
std::cout << "TcpServer Stopping . . . " << std::endl;
//this close is the line that causes the problem...
m_pListener->close();
this->quit();
}
main.cpp
#include <QCoreApplication>
#include <iostream>
#include <QTcpServer>
#include "tcpserver.h"
#include "tcpserverthread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TcpServerThread *t = new TcpServerThread();
t->Start();
t->Stop();
return a.exec();
}
如果注釋掉對main中t-> Stop的調用,則可以運行它並使用telnet(或膩子)以127.0.0.1:1234連接到它。
我想這樣做,以便可以停止它,然后再次啟動它,並且連接將起作用。
好的,所以您將在這里以錯誤的方式使用QThread。 如果要從QThread繼承,那應該是因為您想擴展線程功能,而這並不是您想要的。
QThread是用於控制線程的類,對您而言,它不應成為您的類的一部分。 相反,您應該按自己的方式設計類TcpServer
(而不是TcpServerThread
),但刪除線程元素。 然后創建run(),start()和stop()插槽。 另外,您需要從QObject繼承以使用信號和插槽。 像這樣:
class TcpServer: public QObject
{
Q_OBJECT // don't forget this
:
:
}
然后在main中可以創建線程和類,然后將類移入線程:
TcpServer *pTcpServer = new TcpServer();
QThread *pThread = new QThread;
pTcpServer->moveToThread(pThread);
// Connect thread start to your run() function
connect(pThread, &QThread::started, pTcpServer, &TcpServer::run, Qt::QueuedConnection);
// Now run your thread, when it starts your run() slot will be called
thread->start();
至於呼叫您的啟動/停止-是什么觸發了啟動/停止? 我假設某些其他對象將啟動/停止服務器,或發生某些事件? 無論如何,您將以相同的方式連接它們:
connect(pSomeClass, &SomeClass::startTcpServer, pTcpServer, &TcpServer::start, Qt::QueuedConnection);
connect(pSomeClass, &SomeClass::stopTcpServer, pTcpServer, &TcpServer::stop, Qt::QueuedConnection);
注意
我認為您看到主線程中創建了一些對象的原因是因為您直接在類中調用函數( start()
/ stop()
)。 跨線程“邊界”執行此操作並不安全,因為將在調用線程(主線程)內執行任何操作(或分配的對象)。 您需要使用插槽/信號機制(或其他一些線程安全機制)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.