Antkillerfarm Hacking V7.0

Qt, WebService, 负载均衡

2015-06-02

Qt

Qt主循环

这篇文章有个大概的比较和说明:

http://blog.chinaunix.net/uid-20754930-id-1877623.html

GUI主循环设计及其在MiniGUI, GTK, QT的实现

以下是我针对Qt5代码(2015.4)的一个研究。

QApplication::exec

QGuiApplication::exec

QCoreApplication::exec

QEventLoop::exec

QEventLoop::processEvents

QEventDispatcher::processEvents

再以下就和具体的平台相关了。

Windows平台:

QEventDispatcherWin32::processEvents

它的实现主要是GetMessage+WaitForMultipleObjects,如上文中对MiniGUI的主循环所述。

Unix平台:

QEventDispatcherUNIX::processEvents

QEventDispatcherUNIXPrivate::doSelect

这个函数主要使用select系统调用来监听事件源。

Android平台:

QAndroidEventDispatcher::processEvents

QUnixEventDispatcherQPA::processEvents

QEventDispatcherUNIX::processEvents

以下和Unix平台相同。

Qt多线程中connect的使用

近日在研究OpenGL多线程处理时,偶然看到了如下代码:

http://download.csdn.net/detail/zhoukuanbin/7669187

没有CSDN账号的读者,也可以在这里下载:

https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/Qt/MyGlTest

粗看代码,发现并无特殊的OpenGL处理,理论上应该无法达到一个线程处理渲染,另一个线程处理贴图的目标。但实际编译运行代码,又确实可用。因此这里面一定有什么原因。

void ThreadGl::run()
{
    connect(this, SIGNAL(SigCopy()), this, SLOT(Copy()));
    printf("ID 0:%x\n", currentThreadId());
    while(1)
    {
        if(!m_bEndFlag)
        {
            break;
        }

        usleep(16000);
        emit SigCopy();
    }

    qDebug("Copy End\n");
}

void ThreadGl::Copy()
{
    m_glWidgets -> OnTimeOut(m_pImage, m_Formal, m_pthId);
}

这段代码引起了我的注意。粗一看,connect函数连接的SIGNAL和SLOT都属于同一个对象。而connect函数的第5个参数(这是个有默认值的可省略参数)的默认值为Qt::AutoConnection。

这是Qt官方对Qt::AutoConnection的解释:

  • If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.

按照字面上的意思,既然SIGNAL和SLOT都属于同一个对象,那么这里的Qt::AutoConnection就等同于Qt::DirectConnection。而Qt::DirectConnection与直接调用SLOT函数是一个效果。

于是这里将emit SigCopy();替换为Copy();,结果程序运行出错。

再试一下,将connect函数的第5个参数设为Qt::DirectConnection,同样有问题。

而如果将之设为Qt::QueuedConnection的话,程序运行一切正常。

综上,Qt在这里的处理,显然认为SIGNAL和SLOT属于不同的线程。

那么判断的依据是什么呢?

这里有必要对emit SigCopy();emit背后的戏法做一个剖析。

众所周知,emit并非C++关键字,而属于Qt扩展的一部分。Qt为了处理这些扩展,引入了moc工具作为预处理工具。

而moc处理之后,emit SigCopy();就变成了QMetaObject::activate

QMetaObject::activate中使用以下代码,判定信号接收者的线程是否和信号发送者的一致。

const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId;

于是问题转化为receiver->d_func()->threadData是怎么来的呢?

答案在QObject::QObject中:

d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();

从这里可以看出所谓信号接收者的线程,实际上是接收者对象创建时所处的线程。

回到原来的问题。ThreadGl虽然是Qt的线程对象,但它本身却是在主线程中创建的,所以以它为接收者,实际上就是以主线程为接收者。

显然这个例子代码并没有真正实现OpenGL多线程处理,所有的OpenGL操作实际上都是在主线程完成的。

参考:

https://blog.csdn.net/feiyangqingyun/

一个Qt的blog

PyQt

PyQt是一个python语言的Qt封装。除此之外,还有一个叫PySide的库也是干这个的。

它们的区别在于:PyQt是Riverbank Computing开发的,历史早,功能强。PySide是Qt官方提供的,然而很久以来都比不过前者。。。

https://mp.weixin.qq.com/s/jNa4JTefasFDWoGJDBL6-Q

PyQt编写GUI界面

https://mp.weixin.qq.com/s/sR1R2DRA2XASx9LJExasfA

15个开源示例手把手带你用PyQt做小型桌面应用

参考

https://zhuanlan.zhihu.com/p/35081519

Qt模拟Linux终端Terminal与系统交互(QProcess)

WebService

WebService经过近二十年的发展,已经有非常多的框架了。知名的有:Axis1、Axis2、Xfire、CXF、JWS等。

其中的JWS在JDK 1.6之后被集成到JDK中,成为了我学习的首选。

JWS包含了JAX-WS、JAX-RS、JAXB、JAXR、SAAJ、StAX等组件。这里主要涉及的是JAX-WS。

教程

参考:

http://www.blogjava.net/zjhiphop/archive/2009/04/29/webservice.html

java调用webservice的各种方法总结

http://blog.csdn.net/lifetragedy/article/details/7205832

5天学会jaxws-webservice编程

以上两篇是中文blog。

http://java.globinch.com/enterprise-java/web-services/jax-ws/java-jax-ws-tutorial-develop-web-services-clients-consumers/

这个教程虽然是英文的,但质量超过前两篇。且该网站还有其他相关文章,质量也颇高。

demo

本文相关的demo参见:

https://github.com/him-bhar/jax-ws

这个demo包括jaxws-demo、jaxws-demo-client-stubs和jaxws-demo-client三个模块。

使用这个demo会有若干问题,也可直接采用本人修改之后的代码:

https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/java/jax-ws

开发模型

JAX-WS 2.0有两种开发过程:自顶向下自底向上。自顶向下方式指通过一个WSDL文件来创建Web Service,自底向上是从Java类出发创建Web Service。

demo选用Server端通过Java Class生成webservice,而客户端通过wsdl生成Java调用类的做法。

这种方法的优点在于:

1.服务端开发基于Java,基本不需要对WSDL有过多研究,上手简单。

2.客户端通过wsdl生成Java调用类,可以很方便的导入第三方WebService,同样无需对WSDL有过多研究。

综上,这实际上是个由服务端驱动的开发模型

jaxws-demo的结构

jaxws-demo包含了两个WebService例子分别是rpc_type和document_type。

这两种类型实际上指的是SOAP Binding的类型。两者的区别参见:

http://java.globinch.com/enterprise-java/web-services/soap-binding-document-rpc-style-web-services-difference/

吐槽一下,虽然这只是个基本的问题,然而中文blog中竟然没有令人满意的文章。
这些文章的毛病在于:
1.对Java和JWS过于细节,而忽视了交互报文。SOAP Binding类型主要是个通讯协议问题,而不是Java或者JWS的问题。
2.没有比较交互报文,就来笼统的谈各自的优缺点的,都是耍流氓。

从上文的交互报文可以看出,document_type虽然更复杂,但也更灵活。从直观来看,前者只有wsdl一个文件,而后者有wsdl和xsd两个文件。

jaxws-demo的部署

jaxws-demo编译之后,除了生成相应的.class之外,还会生成对应的wsdl和xsd文件。

通常的做法是将这些文件一起部署到诸如Tomcat之类的Web容器中。

但JDK也提供了更简易的做法,使用javax.xml.ws.Endpoint类的publish方法,将WebService绑定到特定的URI上。

这里我们将com.himanshu.poc.jaxws.service.deploy.EndpointPublisherDocument设为主类,并执行程序。

在浏览器上输入:

http://localhost:9999/ws/hellodocument?wsdl

正常情况下会返回一个wsdl文件。

jaxws-demo-client-stubs

JDK中,有两个和WebService相关的工具:

JAXWS为我们提供了两个工具:

wsgen。主要用于Server端通过Java类编译成Webservice及相关的wsdl文件。

wsimport。主要用于Client端(调用端)通过wsdl编译出调用Server端的Java文件。

jaxws-demo中,调用wsgen生成的wsdl和xsd文件,在这里被wsimport编译成客户端的桩代码。

由于我使用的JDK是JDK 1.8,因此会遇到如下问题:

由于 accessExternalSchema属性设置的限制而不允许 'file' 访问, 因此无法读取方案文档'xjc.xsd'。

解决方法:

<plugin>
    <groupId>org.jvnet.jax-ws-commons</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <!-- Needed with JAXP 1.5 -->
        <vmArgs>
            <vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
        </vmArgs>
    </configuration>
</plugin>

这个问题是由于JDK 1.8以后相关权限变得更加严格所导致的。

参见:

https://my.oschina.net/fuckmylife0/blog/325432

jaxws-demo-client

jaxws-demo-client就是具体的客户端实现了,可以看出相比于上一步的桩代码,这里的代码文件,数量上要少得多。

负载均衡

正向代理,“它代理的是客户端,代客户端发出请求”。

反向代理,“它代理的是服务端,代服务端接收请求”。

http://blog.csdn.net/gzh0222/article/details/8540604

lvs、haproxy、nginx负载均衡的比较分析

https://mp.weixin.qq.com/s/SO1ZLSPaRkk8WwUl9u-JPA

仅需这一篇,吃透“负载均衡”妥妥的

https://mp.weixin.qq.com/s/3KZ99d94yqRDxEByn7nGWg

QPS比Nginx提升60%,阿里Tengine负载均衡算法揭秘

https://mp.weixin.qq.com/s/XsyXkaOIJ3m8sdCt8Pl5Ig

计算密集型服务的负载均衡策略

https://mp.weixin.qq.com/s/SmpUPJRK0TMdA0rkb_Q6VQ

什么是集群?什么又是负载均衡?

https://mp.weixin.qq.com/s/sCGI3XPga5gTZF0iskJlMA

全网最详尽的负载均衡原理图解

https://mp.weixin.qq.com/s/o5lTN4IpHmZqLUKoJsSyKw

爱奇艺TFServing负载均衡问题研究及改进实践

Nginx

https://mp.weixin.qq.com/s/31DGDYpDHcYg-4qM4OczxA

深入浅出Nginx

https://mp.weixin.qq.com/s/h9sXZc4Y62f4KOSVXAB1Pg

Nginx基本功能极速入门

https://www.cnblogs.com/wcwnina/p/8728391.html

Nginx相关介绍

https://mp.weixin.qq.com/s/aCAuJQEB2pmL92OTEb_4Xg

Nginx为什么这么快?

https://mp.weixin.qq.com/s/3GSuB1tLe-G5hZPUiAXuVA

Nginx,为什么依旧这么“香”?

https://blog.csdn.net/yujing1314/article/details/107000737

搞懂Nginx一篇文章就够了

https://mp.weixin.qq.com/s/-8Ka8nMYpH7cipzfm36utw

写给小白的Nginx文章

https://mp.weixin.qq.com/s/gd59U50tlJPa4B4avXRG1Q

Nginx架构浅析

https://mp.weixin.qq.com/s/eUindWNZiCv_tSLQeYfmLg

Nginx常用配置清单

https://mp.weixin.qq.com/s/LmtHTOVOvdcnMBuxv7a9_A

Nginx最全操作总结

Fork me on GitHub