博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Qt搭建多线程Server
阅读量:6956 次
发布时间:2019-06-27

本文共 2495 字,大约阅读时间需要 8 分钟。

起因是MySQL在Android上没有驱动。也就是说,移动端想要访问远程数据库,必须通过一台(或多台)PC进行中转。

中转PC作为Server,接受来自移动端Socket访问数据库的要求,Server访问数据库,取得数据,通过Socket发送给移动端。

Qt写个C/S其实很简单,网上各种教程,硬伤:Server!是!单!线!程!

假设有10000个移动端访问中转Server,那么如果Server是单线程,那么这10000个移动端是排队通信,排队访问数据库,肯定完蛋!

所以Server必须使用多线程。

Qt的多线程是个经常让新手搞错的东西,很多文章中看起来是多线程,实际上根本就是单线程。

默认的C/S连接方式(acceptConnection)不支持多线程也是硬伤!

于是搞了好久,总算搞定了多线程Server。

 

 

①首先写Server类,派生自QTcpServer, 只要重载 incomingConnection 这个虚函数就行了。

无须像单线程那样  connect(&server,SIGNAL(newConnection()),this,SLOT(acceptConnection()));

void Server::incomingConnection (qintptr socketDescriptor){    SocketThread *thread = new SocketThread(socketDescriptor,this);    Processor *cpu=new Processor(thread->socket);    connect(thread->socket,SIGNAL(readyRead()),cpu,SLOT(work()));    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));    cpu->moveToThread (thread);    thread->start();}

在这个函数里有几个陌生的玩意。

SocketThread类 派生自QThread,子线程不解释。

Processor类 派生自 QObject,这个类是重点。

Qt多线程的最大问题在于,除了子线程的run函数是跑在子线程里,线程其它函数(包括信号/槽)都是跑在主线程里。

我们的Server肯定要处理Client的请求,也就是Socket的数据请求,在Qt里,这步被封装在Socket的readyRead信号里。

就算你在run函数里绑了readyRead信号,最后信号还是会在主线程里触发。

解决方案是单独写个处理类,这里就是Processor类,将子线程moveThread到这个对象中,这样这个对象的所有函数都是在子线程里执行了,work函数用于Server接受请求以及返回数据库数据。

这是Qt 4.7之后,官方的推荐写法,因为N多人的多线程写的根本就是错的,官方实在忍不了了。  

 

②再看 SocketThread类

class SocketThread : public QThread{    Q_OBJECTpublic:    SocketThread(int socketDescriptor,QObject* parent);    int socketDescriptor;    QTcpSocket *socket;    void run();};SocketThread::SocketThread(int id,QObject *parent):QThread(){    socketDescriptor=id;    socket=new QTcpSocket;}void SocketThread::run (){    socket->setSocketDescriptor(socketDescriptor);    QThread::run ();}
Thread

构造函数不用多说,传入系统为Server分配的Socket的识别id。

关键就是QThread的虚函数run。首先设置Server的Socket识别id。

记得调用 QThread::run ();  否则这个run函数并没有完全执行。

 

③再看Processor类

void Processor::work (){    //qDebug()<<"当前线程: "<
readAll (); m_socket->write (buff); //qDebug()<
<
Processor

成员就一个指针m_socket,保存子线程的socket地址。

以及一个QByteArray作为缓冲区buff。

readAll读取Client的Socket,write写回Client的Sokcet。

无聊的话可以把注释拿掉,看看work函数的工作线程是否与主线程不同。

 

④Client端

void Client::send (){    socket->connectToHost(QHostAddress(address->text ()),7399);    QString x="2333,要完蛋了 "+QString::number (cnt++);    socket->write(x.toStdString ().c_str ());}void Client::get (){    QString data=socket->readAll();    qDebug()<<"接收端:"<<
disconnectFromHost ();}

这里使用的策略如下:

每发一个请求,连一次Server,收到Server的回复后,断开连接,防止占用Sever资源。

get函数作为Client的readyRead的槽函数就行了。

 

转载地址:http://gpmil.baihongyu.com/

你可能感兴趣的文章
DAC--解决windows验证无法登陆的问题
查看>>
[CALayer release]: message sent to deallocated instance iOS内存过度释放问题
查看>>
WPF界面设计技巧(4)—自定义列表项样式
查看>>
git push的时候每次都要输入用户名和密码的问题解决
查看>>
精益开发实战:用看板管理大型项目
查看>>
hiho_1138_island_travel
查看>>
Redis内存存储结构分析
查看>>
love2d教程13--图形界面
查看>>
POJ 1276 Cash Machine
查看>>
C语言中 struct成员变量顺序对内存的占用
查看>>
POJ1291-并查集/dfs
查看>>
移动办公首选!电商热卖轻薄本高低该怎么选?
查看>>
[译] RNN 循环神经网络系列 1:基本 RNN 与 CHAR-RNN
查看>>
Android技能树 — PopupWindow小结
查看>>
如何在create-react-app项目中使用vw实现手淘vw移动端适配布局
查看>>
Wormhole燃烧地址到底有多安全
查看>>
Web探索之旅 | 第三部分第三课:协议
查看>>
20个优秀手机界面扁平化设计,让你一秒看懂扁平化
查看>>
从百度的PPT文化看程序员晋升
查看>>
Python测试登录功能
查看>>