QT控制台TCP通信,为每个客户端分配⼀个独⽴的线程(重
写incomingConnecti。。。
QTcpServer若为每个客户端分配⼀个独⽴线程,必须重写incomingConnection()函数。
为何不直接把nextPendingConnection()函数返回的socket指针⽤在线程中?
在该函数的帮助中,QT明确表⽰:不能在线程中调⽤QTcpServer⾃动创建的QTcpSocket对象。并且在incomingConnection()的帮助中有提到,如若将客户端的连接传⼊单独的线程,则QTcpSocket对象必须创建在线程中,socket对象的创建通过重写incomingConnection()函数实现。
QTcpServer类的⼯作机制是在有传⼊连接时,QTcpServer会创建⼀个与客户端匹配的socket,并返回⼀个指向socket内存的socketDescriptor(socket描述符),在QT中该描述符是qintptr类型的。然后QTcpSer v er会⾃动调⽤incomingConnection()函数,该函数接收这个socketDescriptor。
在incomingConnection()函数的原实现中,创建了⼀个QTcpSocket对象,然后调⽤函数
QTcpSocket::setSocketDescriptor(qintptr socketDescriptor)设置socket描述符。最后在incomingConnection()函数中⼜调⽤了addPendingConnection(QTcpSocket * socket),将创建的QTcpSo
cket对象指针挂起在已创建列表中,该⾏为可终⽌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
{pending
QTcpSocket * socket;
qintptr socketDescriptor;
public:
QTcpThread(qintptr s) : QThread()
{
socketDescriptor = s;
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,否则错误或超出最⼤延迟则返回false
socket->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会使⽤socketDescriptor
QTcpThread * 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();
();
}
客户端:
#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};
qDebug() <<" 进⼊连接等待,最长5秒..." << endl;
if (socket1.waitForConnected(5000))//连接等待,如果connectToHost连接成功,则⽴即返回true,否则到达最延迟后返回false qDebug() << "已连接!" << endl;
else{
qDebug() << "连接失败!" << endl;
socket1.close();
();
}
while(socket1.state()&&QAbstractSocket::ConnectedState)
{
socket1.write((char*)&stu,sizeof(Stu)); //发送⼀个结构体,以⼆进制格式发送
socket1.waitForBytesWritten();//发送等待,只要write发送出第⼀个字符时,⽴即返回true,否则到达最⼤延迟后返回false Wait(3000);
}
socket1.close();
();
}
运⾏结果截图:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论