起因是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. 设计模式学习之装饰者模式(Decorator,结构型模式)(16)

    参考地址:http://www.cnblogs.com/zhili/p/DecoratorPattern.html 一.定义:装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相 ...

  3. Linux Shell 高级编程技巧3----运行级别脚本介绍

    3.运行级别脚本介绍    3.1.运行级别        运行级别介绍:            0    关机            1    单用户模式            2    多用户模式 ...

  4. ExcelReport第三篇:扩展元素格式化器

    导航 目   录:基于NPOI的报表引擎——ExcelReport 上一篇:ExcelReport源码解析 概述 上篇中已介绍了ExcelRepor的架构,本篇将通过例子讲述如何扩展元素格式化器以满足 ...

  5. xml解析方法总结

    ==========================================xml文件<?xml version=”1.0″ encoding=”GB2312″?> <RES ...

  6. android 入门-工程属性介绍

    工程属性 (1)drawable-hdpi里面存放高分辨率的图片,如WVGA (480x800),FWVGA (480x854) (2)drawable-mdpi里面存放中等分辨率的图片,如HVGA ...

  7. loj 1426(dfs + bfs)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1426 思路:首先我们预处理出每一个"*"在某一方向上最终能到达的位 ...

  8. git warning: LF will be replaced by CRLF in...

    如果你有git项目,在提交代码的过程中可能会碰到上面的警告,特别是的项目中包含序列化对象的时候,你可能要小心!! 警告的含义是说换行符的,不同的操作系统的换行符是不一致的,如果你不清楚,真得看看这个 ...

  9. document.body.scrollTop

    标准浏览器:document.documentElement.scrollTop; 谷歌浏览器:document.body.scrollTop; var scrollTop = document.do ...

  10. zepto的bug1

    给页面<a>标签绑定了tap事件,在移动设备上点击按钮貌似一切正常,可以正常响应. 但是,把页面上下滑动几次之后,或者在滑动时手指滑动出移动屏幕之外,之后再点击按钮,就会发现第一次点击的时 ...