在编写一般程序中,通常将通信部分与数据处理部分单独放到一个线程或进程(Python由于GIL锁需要使用进程),这样可保证程序的快速响应,数据处理不会对其他部分造成影响。
在Qt中使用线程有两种方式:一种是继承QThread,重新实现run()函数。此时要注意,只有run()函数里面的才是单独运行到线程中的。通常在run()函数中使用while()循环或for循环与队列配合,让线程一直处理请求。另一种是使用moveToThread()函数将对象移到子线程中,moveToThread()函数之后再做说明,本次主要说明使用QThread时遇到的问题。
这是传说中的UI。。。 ~ ~。。。
一些程序:
#ifndef THREADSOCKET_H
#define THREADSOCKET_H
#include
#include
class ThreadSocket : public QThread
{
Q_OBJECT
public:
ThreadSocket();
void start_thread();
public slots:
void slot_readmesg();
void slot_WritMsgToServer(QString str);
protected:
void run();
private:
QTcpSocket *mp_clsTcpSocket;
bool couldReadData;
};
#endif // THREADSOCKET_H
#include "threadsocket.h"
#include
ThreadSocket::ThreadSocket():
QThread(),
couldReadData(false)
{
qDebug() << "parent this id" << this;
}
void ThreadSocket::start_thread()
{
if(!this->isRunning())
this->start();
}
void ThreadSocket::slot_readMsgFromServer()
{
couldReadData = true;
QByteArray buffer = mp_clsTcpSocket->readAll();
qDebug() <<"msg:"<< buffer;
}
void ThreadSocket::slot_WritMsgToServer(QString str)
{
mp_clsTcpSocket->write(str.toLatin1());
}
void ThreadSocket::run()
{
mp_clsTcpSocket = new QTcpSocket();
mp_clsTcpSocket->connectToHost("192.168.18.77",2115);
connect(mp_clsTcpSocket,SIGNAL(readyRead()),this, SLOT(slot_readMsgFromServer()));
if (mp_clsTcpSocket->waitForConnected(1000))
{
qDebug() << "connect success !";
}else{
qDebug() << "connect faild !";
}
while(1)
{
qDebug() << "__________________";
mp_clsTcpSocket->write("test\n");
mp_clsTcpSocket->flush();
qDebug() << "couldReadData" << couldReadData;
if (true == couldReadData)
{
QByteArray buffer = mp_clsTcpSocket->readAll();
qDebug() <<"receive server msg:"<< buffer;
couldReadData = false;
}
sleep(1);
②// exec();
}
}
简单说下程序构成:所贴代码主要是线程中的socket接收与发送测试代码。主UI中有两个按钮,一个是启动线程,另一个是在通过信号槽向服务器发送数据。
在run()函数中实例化客户端,注意不要传入this指针,否则会报如下错误:QObject: Cannot create children for a parent that is in a different thread.【QObject:无法为位于不同线程中的父级创建子级。】
这样客户端就存在与子线程中,同样在run()中连接信号和槽。注意此时的this是父类的this,即信号与槽位于不同的线程。这是第一个值得注意的地方。
第二该测试中,需要在客户端write()后加flush(),否则客户端无法发送数据。这是第二个需要注意的地方。
第一种测试:
运行该测试程序,可以在run()中向服务器发送数据,但是无法在主UI通过信号和槽的方式向服务器发送数据。点击Send按钮,报错如下:QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread.【QSocketNotifier:无法从另一个线程启用或禁用套接字通知程序】。服务器向客户端发送数据,客户端接收不到,connect()函数返回True,说明信号与槽连接成功。这是上述测试程序的运行结果。
第二种测试:
在sleep(1)后加入 exec()函数,while()循环只执行一次,客户端槽函数可以接收服务器发出的数据。但在主UI中依然无法向服务器发送数据。
这次的内容只描述两种测试结果,接下来的其他内容将逐步剖析这些情况的原因。
一起学习,共同进步。我们都是奋斗者!
欢迎大家关注我的公众号!