我在下面提供了我的全部代码。请原谅我的设计,因为我是 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
tcpserver线程.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();
}
主要.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(或 putty)连接到它 @ 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()
)。跨线程“边界”执行此操作并不安全,因为采取的任何操作(或分配的对象)都将在调用线程(主线程)内完成。您需要使用槽/信号机制(或其他一些线程安全机制)。
关于c++ - 如何在 QThread 上创建 QTcpServer 然后从主线程中停止它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37871892/