起因是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的更多相关文章

  1. 基于QT的多线程server

    // thread.cpp #include "thread.h" Thread::Thread(int socketDescriptor, QObject *parent) : ...

  2. 从0开始搭建SQL Server AlwaysOn 第一篇(配置域控)

    从0开始搭建SQL Server AlwaysOn 第一篇(配置域控) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www.cnb ...

  3. 从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)

    从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www ...

  4. 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)

    从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://w ...

  5. 从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点)

    从0开始搭建SQL Server AlwaysOn 第四篇(配置异地机房节点) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www ...

  6. (转) 从0开始搭建SQL Server AlwaysOn 第三篇(配置AlwaysOn)

    原文地址: http://www.cnblogs.com/lyhabc/p/4682986.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第三篇,这一篇才真正开始搭建Alwa ...

  7. (转)从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)

    原文地址:  http://www.cnblogs.com/lyhabc/p/4682028.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第二篇,主要讲述如何搭建故障转移集 ...

  8. virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续)

    virtualbox搭建ubuntu server nginx+mysql+tomcat web服务器1 (未完待续) 第一次接触到 linux,不知道linux的确很强大,然后用virtualbox ...

  9. 在Windows Server 2012 R2中搭建SQL Server 2012故障转移集群

    需要说明的是我们搭建的SQL Server故障转移集群(SQL Server Failover Cluster)是可用性集群,而不是负载均衡集群,其目的是为了保证服务的连续性和可用性,而不是为了提高服 ...

随机推荐

  1. UISegmentedControl

    1. NSArray *segmentedArray = [[NSArray alloc]initWithObjects:@"1",@"2",@"3& ...

  2. .NET Framework 4 与 .NET Framework 4 Client Profile

    今天碰到的一个问题和Client Profile相关的.问题是这样的:一个WPF工程,需要引用另外几个.NET的assembly, 在WPF工程中添加了对这几个assembly的引用,并在程序中可以添 ...

  3. git checkout 命令详解

    转自:http://www.cnblogs.com/hutaoer/archive/2013/05/07/git_checkout.html?utm_source=tuicool&utm_me ...

  4. hibernate常用配置

    核心配置 核心配置有两种方式进行配置 1:属性文件的配置:hibernate.properties 格式:key=value hibernate.connection.driver_class=com ...

  5. go语言

    Go语言是谷歌推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性.和今天的C++或C一样,Go是一种系统语言. 1.windows开发工具:Golang for Windows ...

  6. Jmeter之csv、用户自定义变量以及Query Type分析(八)

    很多童鞋不知道对于Jmeter的Query Type 不知道选哪个,为什么选,怎么选! 下面这边做个简单的分析, 那么首先什么是CSV Data Set Config,有什么用呢? CSV Data ...

  7. android中随着ScrollView的滑动,titleBar状态的改变

    今天项目有一个需求,,类是于QQ空间里面的一个功能,于是就研究了一下,嗯,说这么多,可能还有人不知道指的是那个,直接上效果图.见谅,不会弄动态图:   对,就是这种效果,我研究了一下,思路如下: 1. ...

  8. caffe安装(linux)

    从官网github下载caffe-master.zip 解压:unzip caffe-master 将Makefile.config.example复制,命名为Makefile.config(如果是C ...

  9. Uva 839 Not so Mobile

    0.最后输出的yes no的大小写 1.注意 递归边界   一直到没有左右子树 即b1=b2=false的时候 才返回 是否 天平平衡. 2.注意重量是利用引用来传递的 #include <io ...

  10. HTML DOM学习之三

    1.创建新的HTML元素:appendChild(); 如需向HTML DOM添加元素,首先必须创建该元素,然后把它追加到已有的元素上: <div id="div1"> ...