Qt搭建多线程Server
起因是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_OBJECT
public:
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()<<"当前线程: "<<QThread::currentThreadId ()<<endl;
buff=m_socket->readAll ();
m_socket->write (buff);
//qDebug()<<buff<<endl;
}
Processor
成员就一个指针m_socket,保存子线程的socket地址。
以及一个QByteArray作为缓冲区buff。
readAll读取Client的Socket,write写回Client的Sokcet。
无聊的话可以把注释拿掉,看看work函数的工作线程是否与主线程不同。
④Client端
void Client::send ()
{
socket->connectToHost(QHostAddress(address->text ()),);
QString x="2333,要完蛋了 "+QString::number (cnt++);
socket->write(x.toStdString ().c_str ());
}
void Client::get ()
{
QString data=socket->readAll();
qDebug()<<"接收端:"<<data<<endl;
socket->disconnectFromHost ();
}
这里使用的策略如下:
每发一个请求,连一次Server,收到Server的回复后,断开连接,防止占用Sever资源。
get函数作为Client的readyRead的槽函数就行了。
Qt搭建多线程Server的更多相关文章
- 基于QT的多线程server
// thread.cpp #include "thread.h" Thread::Thread(int socketDescriptor, QObject *parent) : ...
- 从0开始搭建SQL Server AlwaysOn 第一篇(配置域控)
从0开始搭建SQL Server AlwaysOn 第一篇(配置域控) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www.cnb ...
- 从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)
从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www ...
- 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)
从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://w ...
- 从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点)
从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www ...
- (转) 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)
原文地址: http://www.cnblogs.com/lyhabc/p/4682986.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第三篇,这一篇才真正开始搭建Alwa ...
- (转)从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)
原文地址: http://www.cnblogs.com/lyhabc/p/4682028.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第二篇,主要讲述如何搭建故障转移集 ...
- virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续)
virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续) 第一次接触到 linux,不知道linux的确很强大,然后用virtualbox ...
- 在Windows Server 2012 R2中搭建SQL Server 2012故障转移集群
需要说明的是我们搭建的SQL Server故障转移集群(SQL Server Failover Cluster)是可用性集群,而不是负载均衡集群,其目的是为了保证服务的连续性和可用性,而不是为了提高服 ...
随机推荐
- linux中创建gpio节点
转自:http://blog.chinaunix.net/uid-29165999-id-4296162.html #define GPIO_MAJOR 230 // major device NO. ...
- OCJP(1Z0-851) 模拟题分析(八)over
Exam : 1Z0-851 Java Standard Edition 6 Programmer Certified Professional Exam 以下分析全都是我自己分析或者参考网上的,定有 ...
- poj 1008:Maya Calendar(模拟题,玛雅日历转换)
Maya Calendar Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 64795 Accepted: 19978 D ...
- Centos 上使用Mono+MVC5+WebApi+Sqlite
鉴于现在网上很多Mono安装Jexus的方法已经过时,你打开百度搜索基本是几个前辈写的文字,很多其实是过去式了.踩的坑多自然使人望而生畏,而方便快捷的方法百度排名却太低,这里就安利下笔者刚成功使用的方 ...
- 2-06使用SQL语句创建数据库3
向现有数据库中添加文件组和数据文件几种方式以及步骤: 第一种:在视图下添加文件组和数据文件. 添加文件组的步骤: 右击你想要添加文件组的数据库点属性,然后点文件组就可以添加. 添加数据文件的步骤: 下 ...
- PHP导出Excel一个方法轻松搞定
/** * 导出数据为excel表格 *@param $data 一个二维数组,结构如同从数据库查出来的数组 *@param $title excel的第一行标题,一个数组,如果为空则没有标题 *@p ...
- [JavaCore] 取得类的字节码、取得类的装载器
三种方式取得类的字节码: 1. 类名.class BranchInfoService.class 2. 对象名.getClass() branchInfoService.getClass() 3. C ...
- 深入分析JavaWeb 技术内幕
1,通过浏览器请求一个资源,会发生以下几种过程 1) http的解析过程,包括对于http请求头和响应头中指令(控制用户浏览器的渲染行为和 服务器的执行逻辑)的解析 2)DNS的解析过程(根据域名获取 ...
- HDU 4251 The Famous ICPC Team Again 主席树
The Famous ICPC Team Again Problem Description When Mr. B, Mr. G and Mr. M were preparing for the ...
- TCP状态转换图详解
以下对几个关键的中间状态进行说明: 三次握手: LISTEN:表示服务器的某个SOCKET处于监听状态,可以进行连接了. SYN_SENT:表示客户端的某个SOCKET与服务器进行connect时,首 ...