QT控制台TCP通信,为每个客户端分配一个独立的线程(重写incomingConnection()函数)

编程入门 行业动态 更新时间:2024-10-25 14:32:08

QT控制台TCP通信,为每个客户端分配一个独立的线程(<a href=https://www.elefans.com/category/jswz/34/1769232.html style=重写incomingConnection()函数)"/>

QT控制台TCP通信,为每个客户端分配一个独立的线程(重写incomingConnection()函数)

QTcpServer若为每个客户端分配一个独立线程,必须重写incomingConnection()函数。

 

为何不直接把nextPendingConnection()函数返回的socket指针用在线程中

        在该函数的帮助中,QT明确表示:不能在线程中调用QTcpServer自动创建的QTcpSocket对象。并且在incomingConnection()的帮助中有提到,如若将客户端的连接传入单独的线程,则QTcpSocket对象必须创建在线程中,socket对象的创建通过重写incomingConnection()函数实现。

        QTcpServer类的工作机制是在有传入连接时,QTcpServer会创建一个与客户端匹配的socket,并返回一个指向socket内存的socketDescriptor(socket描述符),在QT中该描述符是qintptr类型的。然后QTcpSer​​​​​​​ver会自动调用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()函数)

本文发布于:2023-07-28 20:50:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1306826.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:重写   控制台   线程   函数   客户端

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!