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)是可用性集群,而不是负载均衡集群,其目的是为了保证服务的连续性和可用性,而不是为了提高服 ...
随机推荐
- hdu 2159 FATE
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2159 思路:二维完全背包,状态转移方程为: f[j][l]=max(f[j][l],f[j-b[i]] ...
- 三、jQuery--Ajax基础--Ajax全接触--扩展知识(跨域)
- Redis笔记(八)Redis的持久化
Redis相比Memcached的很大一个优势是支持数据的持久化, 通常持久化的场景一个是做数据库使用,另一个是Redis在做缓存服务器时,防止缓存失效. Redis的持久化主要有快照Snapshot ...
- 设计模式学习之适配器模式(Adapter,结构型模式)(14)
参考链接:http://www.cnblogs.com/zhili/p/AdapterPattern.html一.定义:将一个类的接口转换成客户希望的另一个接口.Adapter模式使得原本由于接口不兼 ...
- sdut 2445 小学数学
小学数学 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 题目链接:http://acm.sdut.edu.cn/sdutoj/p ...
- wp8 入门到精通 MultiMsgPrompt
List<NotifyMsg> arraymsg = new List<NotifyMsg>(); List<NotifyInfo> ArrayNotifyInfo ...
- Entity Framework Code First for SQL Compact
这篇博客将介绍EF Code First中如何使用SQL Compact.SQL Compact是微软推出的免费的关系型数据库,目前最新版本是SQL Compact 4.0.微软的开发工具VS 201 ...
- 2015最新移动App设计尺寸视觉规范【图文版】(转)
如今手机app的屏幕设计尺寸参差不齐,仿佛来到了移动界面尺寸战国时代,每家移动设备制造公司都为了迎合大众的口味,各家都在2014年大放光彩.2015年也将会是我们移动APP设计界快速发展的一年. 因为 ...
- X64下MmIsAddressValid的逆向及内存寻址解析
标 题: [原创]X64下MmIsAddressValid的逆向及内存寻址解析 作 者: 普通朋友 时 间: 2015-10-21,20:03:52 链 接: http://bbs.pediy.com ...
- DSP using MATLAB 示例Example3.8
代码: x = rand(1,11); n = 0:10; k = 0:500; w = (pi/500)*k; % [0,pi] axis divided into 501 points. X = ...