我在下面提供了我的全部代码。请原谅我的设计,因为我是Qt的新手,这是一个快速而肮脏的例子。
我想要做的是创建一个管理QTcpServer监听器的QThread。我希望它能够在停止时关闭监听器,然后在重新启动时重新打开它。请忽略听众可能现在被泄露的事实,我稍后会解决这个问题。
我认为问题是当调用Stop时,它调用与其创建的线程不同的线程(从主线程调用)上的m_listener-> close()方法(它是在TcpServerThread上创建的) 。所以问题是,如何修复它?或者我如何重新设计它以避免这个问题?
这不是完整的设计,我制作了一个模仿真实物品的玩具示例。
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();
}
如果你注释掉对t-&gt;主要停止的呼叫你可以运行它并使用telnet(或putty)连接到它@ 127.0.0.1:1234。
我想做到这一点,它可以被停止然后再次启动,连接将起作用。
答案 0 :(得分:2)
好的,所以你在这里以错误的方式使用QThread。如果你要从QThread继承那么这应该是因为你想扩展线程的功能,这不是你想要的。
QThread是一个用于控制线程的类,对你来说,不应该是你班级的一部分。相反,您应该设计您的类TcpServer
(而不是TcpServerThread
),但删除线程元素。然后make 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()
)。在线程“边界”执行此操作是不安全的,因为所采取的任何操作(或分配的对象)将在调用线程(主线程)内完成。您需要使用插槽/信号机制(或其他一些线程安全机制)。