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)是可用性集群,而不是负载均衡集群,其目的是为了保证服务的连续性和可用性,而不是为了提高服 ...
随机推荐
- 苹果官方制作MAC OS的启动U盘的步骤
工具/原料 一个8G或者更大容量的U盘 MAC OS系统镜像DMG文件 方法/步骤 1.打开应用程序 - 使用工具里的磁盘工具,将U盘格式化为MAC OS扩展日志式,名称输入Mavericks,并创建 ...
- APP消息推送:通知和透传
目前市场上的消息推送方式有两种:通知和透传.什么是透传?透传即是透明传送,即传送网络无论传输业务如何,只负责将需要传送的业务传送到目的节点,同时保证传输的质量即可,而不对传输的业务进行处理.透传消息, ...
- ASP.NET Web API中使用GZIP 或 Deflate压缩
对于减少响应包的大小和响应速度,压缩是一种简单而有效的方式. 那么如何实现对ASP.NET Web API 进行压缩呢,我将使用非常流行的库用于压缩/解压缩称为DotNetZip库.这个库可以使用Nu ...
- Android Studio 配置
Android配置:[转]原地址:http://www.cnblogs.com/smyhvae/p/4022844.html [开发环境] 物理机版本:Win7旗舰版(64位) Android Stu ...
- 蓝桥杯 算法训练 Torry的困惑(基本型)(水题,筛法求素数)
算法训练 Torry的困惑(基本型) 时间限制:1.0s 内存限制:512.0MB 问题描述 Torry从小喜爱数学.一天,老师告诉他,像2.3.5.7……这样的数叫做质数.Torry突 ...
- JavaScript高级程序设计 读书笔记
第一章 JavaScript 简介 第二章 Html中使用JavaScript 第三章 基本概念 第四章 变量,作用域,内存 第五章 引用类型 第六章 面向对象 第七章 函数表达式 第八章 BOM 第 ...
- WCF消息拦截,利用消息拦截做身份验证服务
本文参考 http://blog.csdn.net/tcjiaan/article/details/8274493 博客而写 添加对信息处理的类 /// <summary> /// 消 ...
- hdu 4070 福州赛区网络赛J 贪心 ***
优先发路程最长的 #include<cstdio> #include<iostream> #include<algorithm> #include<cstri ...
- C语言基本点初探
1,对于int a=10++;此语句错误,为什么呢,对于i++来说,i是一个变量,是把i加1然后赋值给i,然而10不是一个变量所以无法执行加加的语法; 2,运算符的优先级: 赋值运算符<逻辑运算 ...
- Fragment 操作原理
fragment 本质 fragment 本质上是 view 的容器和控制器,fragment 是 activity 的碎片. activity 是什么呢?activity 是四大组件之一,因为 ...