重写incomingConnection()函数)"/>
QT控制台TCP通信,为每个客户端分配一个独立的线程(重写incomingConnection()函数)
QTcpServer若为每个客户端分配一个独立线程,必须重写incomingConnection()函数。
为何不直接把nextPendingConnection()函数返回的socket指针用在线程中?
在该函数的帮助中,QT明确表示:不能在线程中调用QTcpServer自动创建的QTcpSocket对象。并且在incomingConnection()的帮助中有提到,如若将客户端的连接传入单独的线程,则QTcpSocket对象必须创建在线程中,socket对象的创建通过重写incomingConnection()函数实现。
QTcpServer类的工作机制是在有传入连接时,QTcpServer会创建一个与客户端匹配的socket,并返回一个指向socket内存的socketDescriptor(socket描述符),在QT中该描述符是qintptr类型的。然后QTcpServer会自动调用incomingConnection()函数,该函数接收这个socketDescriptor。
在incomingConnection()函数的原实现中,创建了一个QTcpSocket对象,然后调用函数QTcpSocket::setSocketDescriptor(qintptr socketDescriptor)设置socket描述符。最后在incomingConnection()函数中又调用了addPendingConnection(QTcpSocket * socket),将创建的QTcpSocket对象指针挂起在已创建列表中,该行为可终止waitForNewConnection()的阻塞,并且用户可以通过调用nextPendingConnection()函数获得这个QTcpSocket对象指针。在线程版的incomingConnection()函数中,可以省略这步addPendingConnection()的调用,因为不再需要通过nextPendingConnection()函数来获得socket指针了。
重写incomingConnection()函数
根据上面QTcpServer类的工作机制,我们尝试实现一个用于多线程的incomingConnection()函数。
重写函数需要创建一个QTcpServer类的派生类,另外还需创建一个线程类。
代码:
服务端:
#include <iostream>
#include <QCoreApplication>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QTime>
#include <QThread>
using namespace std;void Wait(unsigned int T)//延迟暂停,参数毫秒
{QTime wait;//用于延迟wait.start();while ((unsigned int)wait.elapsed() < T)QCoreApplication::processEvents();
}//每一个新的客户端连接,都会由QTcpServer通过重写的incomingConnection()自动分配一个新的线程。
//线程只接受了一个QTcpServer提供的socketDescriptor。
//QTcpSocket类的setSocketDescriptor()函数接收这个socketDescriptor,并利用它完成与客户端的连接。
class QTcpThread : public QThread
{QTcpSocket * socket;qintptr socketDescriptor;
public:QTcpThread(qintptr s) : QThread(){socketDescriptor = s;}void run() //重写QThread虚函数 run(){struct Stu{char ar[8];int b;};Stu stu1;QTcpSocket * socket_ = new QTcpSocket;socket = socket_;socket->setSocketDescriptor(socketDescriptor);while(socket->state()&&QAbstractSocket::ConnectedState){if (socket->waitForReadyRead(1000)){//如果有新数据可供阅读,则立即返回true,否则错误或超出最大延迟则返回falsesocket->read((char*)&stu1,sizeof(Stu)); //接收一个结构体,以二进制cout << stu1.ar << " " << stu1.b << endl;}}}~QTcpThread(){socket->close();delete socket;}
};//重写incomingConnection(),用于在线程中使用socket。
//对于重写incomingConnection()函数,QTcpServer的原则是,必须满足:该函数执行完之后,已创建了一个QTcpSocket对象,并且已设置好
//了其形参中传入的socket描述符“socketDescriptor”。
class NewQTcpServer : public QTcpServer
{//链表 用于释放QTcpThread对象内存struct Dlt{QTcpThread * thread_dlt;Dlt * next;};Dlt * dlt_ = 0;
public:NewQTcpServer(QObject * parent = Q_NULLPTR) : QTcpServer(parent){}protected:void incomingConnection(qintptr socketDescriptor){//将socketDescriptor传入新创建的线程对象,线程启动后QTcpSocket会使用socketDescriptorQTcpThread * thread = new QTcpThread(socketDescriptor);//保存新创建的线程对象指针到链表Dlt * dlt = new Dlt;dlt->thread_dlt = thread;dlt->next = dlt_;dlt_ = dlt;//启动线程 自动会执行run()函数thread->start();}
public:~NewQTcpServer(){Dlt * d;while (dlt_){d = dlt_->next;delete dlt_;dlt_ = d;}}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);cout << "Server side!!" << endl;NewQTcpServer server;server.listen(QHostAddress::Any,50002);Wait(1000000);cout << "Connection close" << endl;server.close();getchar();return a.exec();
}
客户端:
#include <iostream>#include <QCoreApplication>#include <QTcpSocket>
#include <QHostAddress>#include <QTime>//设置延迟函数和计算执行时间using namespace std;
void Wait(unsigned int T)//延迟暂停,参数毫秒
{QTime wait;//用于延迟wait.start();while ((unsigned int)wait.elapsed() < T)QCoreApplication::processEvents();
}
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);cout << "Client side!!" << endl;QTcpSocket socket1;struct Stu{char ar[8];int b;};Stu stu={"zw",24};socket1.connectToHost(QHostAddress("192.168.100.101"),50002);//设置连接信息,并尝试连接qDebug() <<" 进入连接等待,最长5秒..." << endl;if (socket1.waitForConnected(5000))//连接等待,如果connectToHost连接成功,则立即返回true,否则到达最延迟后返回falseqDebug() << "已连接!" << endl;else{qDebug() << "连接失败!" << endl;socket1.close();return a.exec();}while(socket1.state()&&QAbstractSocket::ConnectedState){socket1.write((char*)&stu,sizeof(Stu)); //发送一个结构体,以二进制格式发送socket1.waitForBytesWritten();//发送等待,只要write发送出第一个字符时,立即返回true,否则到达最大延迟后返回falseWait(3000);}socket1.close();return a.exec();
}
运行结果截图:
更多推荐
QT控制台TCP通信,为每个客户端分配一个独立的线程(重写incomingConnection()函数)
发布评论