`
izuoyan
  • 浏览: 9284506 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多

2 QT通信机制

为了更好的实现QT的信息交互,在QT系统中创建了较为完善的通信机制。QT的通信可分为QT内部通信和外部通信两大类。对于这两类通信机制及应用场合做如以下分析:

2.1 QT内部对象间通信

在图形用户界面编程中,经常需要将一个窗口部件的变化通知给窗口的其它部件使其产生相应的变化。对于这种内部对象间的通信,QT主要采用了信号和槽的机制。这种机制是QT区别于其他GUI工具的核心机制。在大部分的GUI工具中,通常为可能触发的每种行为通过定义回调函数来实现。这种回调函数是一个指向函数的指针,在进行函数回调执行时不能保证所传递的函数参数类型的正确性,因此容易造成进程的崩溃。

QT中,信号和槽的机制取代了这种繁杂的、易崩溃的对象通信机制。信号是当对象状态改变时所发出的。槽是用来接收发射的信号并响应相应事件的类的成员函数。信号和槽的连接是通过connect()函数来实现的。例如,实现单击按钮终止应用程序运行的代码connect(button , SIGNAL(clicked()) , qApp , SLOT(quit()) );实现过程就是一个button被单击后会激发clicked信号,通过connect()函数的连接qApp会接收到此信号并执行槽函数quit()。在此过程中,信号的发出并不关心什么样的对象来接收此信号,也不关心是否有对象来接收此信号,只要对象状态发生改变此信号就会发出。此时槽也并不知晓有什么的信号与自己相联系和是否有信号与自己联系,这样信号和槽就真正的实现了程序代码的封装,提高了代码的可重用性。同时,信号和槽的连接还实现了类型的安全性,如果类型不匹配,它会以警告的方式报告类型错误,而不会使系统产生崩溃。

2.2 QT与外部设备间通信

QT与外部通信主要是将外部发来的消息以事件的方式进行接收处理。外部设备将主要通过socketQT应用程序进行连接。在此,以输入设备与QT应用程序的通信为例说明QT与外部通信的原理。

QT的应用程序开始运行时,主程序将通过函数调用来创建并启动qwsServer服务器,然后通过socket建立该服务器与输入硬件设备的连接。服务器启动后将会打开鼠标与键盘设备,然后将打开的设备文件描述符fd连接到socket上。等到QT应用程序进入主事件循环时,事件处理程序将通过Linux系统的select函数来检测文件描述符fd的状态变化情况以实现对socket的监听。如果文件描述符fd状态改变,说明设备有数据输入。此时,事件处理程序将会发出信号使设备输入的数据能及时得到QT应用程序的响应。数据进入服务器内部就会以事件的形式将数据放入事件队列里,等待QT客户应用程序接收处理。处理结束后再将事件放入请求队列里,通过服务器将事件发送到相应硬件上,完成外部输入设备与QT应用程序的整个通信过程。

1 输入硬件设备与应用程序间的通信原理

3 QProcess机制分析

QProcess类通常是被用来启动外部程序,并与它们进行通信的。QProcess是把外部进程看成是一个有序的I/O设备,因此可通过write()函数实现对进程标准输入的写操作,通过read(),readLine()和getChar()函数实现对标准输出的读操作。

3.1 QProcess通信机制

QT可以通过QProcess类实现前端程序对外部应用程序的调用。这个过程的实现首先是将前端运行的程序看成是QT的主进程,然后再通过创建主进程的子进程来调用外部的应用程序。这样QProcess的通信机制就抽象为父子进程之间的通信机制。QProcess在实现父子进程间的通信过程中是运用Linux系统的无名管道来实现的,因此为了能更加清楚的说明QProcess的通信机制,在此首先介绍关于无名管道实现父子进程间的通信机制。

无名管道是一种只能够在同族父子之间通信,并且在通信过程中,只能从固定的一端写,从另一端读的单向的通信方式。该无名管道是通过调用pipe()函数而创建的。创建代码如下:

创建后经参数fd返回两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。经过fork()函数创建其子进程后,子进程将拥有与父进程相同的两个文件描述符。如果想要实现父进程向子进程的通信则关闭父进程的读端fd[0],同时关闭子进程的写端fd[1]。这样就建立了从父进程到子进程的通信连接。

2.1 fork之后的半双工管道 图2.2 从父进程到子进程的管道

由于无名管道的单向通信性,所以如果要应用无名管道实现父子进程之间的双向通信则至少需要应用双管道进行通信。QProcess类的通信原理就是利用多管道实现了父子进程之间的通信。然而对于外部运行的应用程序大都是通过标准输入而读得信息,通过标准输出而发送出信息,因此只通过建立管道并不能完成内外进程?之间的通信。要解决此问题,就如该模块开始时所说,QProcess是把外部进程看成是一个I/O设备,然后通过对I/O设备的读写来完成内外进程的通信。

注:上面所说的外进程其实就是主进程的子进程。由于外部应用程序是在子进程中被调用执行的,因此父子进程间的通信目的还是要实现与外部应用程序的通信。

QProcess中父子进程之间是通过管道连接的,要实现子进程能从标准输入中读得父进程对管道的写操作,同时父进程能从管道中读得子进程对标准输出或标准容错的写操作,就要在子进程中将管道的读端描述符复制给标准输入端,将另外管道的写端描述符复制给标准输出端和标准容错端,即实现管道端口地址的重定向。这样子进程对标准输入、标准输出及标准容错的操作就反应到了管道中。

QProcess在正常渠道模式下具体实现共用了五个无名管道进行通信。五个管道的描述符分别用childpipe[2]stdinChannelpipe[2]stdoutChannelpipe[2]stderrChannelpipe[2]deathpipe[2]五个数组来保存。deathpipe指代的管道会用在消亡的子进程与父进程之间。当子进程准备撤销时会发送一个表示该子进程消亡的字符给父进程来等待父进程进行处理。stdinChannelpipestdoutChannelpipestderrChannelpipe所指代的管道分别与标准输入,标准输出和标准容错进行绑定,实现了与外部程序的通信。childpipe指代的管道主要是为父子进程之间的通信而建立的。详细过程见原理图2

3 QProcess通信原理

注:在图2中没有画出已经关闭的管道描述符,并且将记录管道描述符的数组名childpipe,stdinChannelpipe,stdoutChannelpipe,stderrChannelpipe缩写为child,stdin,stdout,stderr。由于管道childpipedeathpipe实现的都是父子进程之间的通信,通信原理相同,所以在上图中没有画出deathpipe的通信过程。

在图2中父子进程的所有管道描述符都处于被监听状态。如果在管道中有新数据写入,就会通知相应进程去读。另外图2QProcess在正常渠道模式下的通信原理图,如果是在融合渠道模式下,将没有容错管道,此时原理图中将没有第一个管道,也就不会有管道描述符。同时,标准容错端和标准输出端将共同挂接到子进程的stdoutChannelpipe的写端,来实现内外进程的通信。

3.2 QProcess应用方式

由于QProcess类实现了对底层通信方式较为完善的封装,因此利用QProcess类将更为方便的实现对外部应用程序的调用。在此,通过在QT界面中调用外部mplayer的例子来简单说明QProcess的应用方式。

1 constQStringmplayerPath("/mnt/yaffs/mplayer");

2 const QString musicFile("/mnt/yaffs/music/sound.mp3");

3 QProcess*mplayerProcess=newQProcess();
4 QStringListargs;

5 args<<"-slave";
6 args<<"-quiet";

7 args<<"-wid";

8 args<<musicFile;

9 mplayerProcess->setProcessChannelMode(QProcess::MergedChannels);
10 myProcess->start(mplayerPath,args);

第一行指明了所要调用的外部应用程序mplayer的位置。第二行指明了所要播放的歌曲文件及地址。第五行设置mplayer为后台模式。在此模式下,mplayer将从标准输入中读得信息,并通过标准输出向主进程发送信息。六七行为mplayer运行的参数。第九行为设置进程渠道的模式为融合模式,即将标准输出和标准容错绑定到同一个管道的写端。第十行为启动外部应用程序mplayer。内核中管道及通信环境的建立都是在此步中完成的。

mplayerslave模式下运行会自动从标准输入中读取信息并执行。由QProcess的通信原理可知,管道的读端描述符stdinChannelpipe[0]复制给了标准输入,即标准输入的描述符也为stdinChannelpipe[0],因此按照标准输入的描述符去读信息就是到stdinChannelpipe所对应的管道中读取信息。所以如果想在QT的主进程中发送命令使mplayer退出,只需在主程序中向stdinChannelpipe[1]端写入命令quit就可以,执行语句为myProcess->write(”quit\n”;(此处的write()函数为QProcess类的成员函数,具体实现就是向stdinChannelpipe[1]端写入信息)

3.3 QProcess的发展及分析

QProcess类伴随着QT/Embedded的发展逐渐趋于完善。在QTE2及其更前版本中还没有QProcess类,如果想实现与外部应用程序的通信,必须要自己实现对管道或socket的建立与重定向。到了QTE3版本,就实现了对QProcess类的封装。在QTE3的版本中,QProcess类的实现是通过应用socket来建立主进程与外部应用程序之间通信的。通信原理与图3所示基本相同,只是将图中的管道描述符改为是socket的描述符即可。QT主程序在建立成对socket描述符时需要调用Linux系统函数socketpair()。在生成的成对socket描述符之间可以实现父子进程之间的双向通信,即无论是socket0套接口还是1套接口都可进行读写。

但为了避免出现通信过程中父子进程对同一个socket的争夺,例如,在子进程还未将父进程发送的信息全部读出时,子进程又要求将自己产生的数据返回给父进程。如果父子进程双向通信只用一个socket来完成,就会出现父子进程发送的信息混乱情况。因此,对于QProcess的实现仍然必须通过多个socket来共同完成。

由上面的描述可知,尽管socket有双向通信功能,但在实现QProcess过程中只是利用socket实现了单向通信功能。因此既浪费了对资源的利用又增加了系统的开销。为了解决此问题,QTE4版本将QProcess的通信连接方式由socket改为了只能实现单向通信的无名管道来实现。通信原理就是以上3.1 QProcess通信机制中所描述的。

4 其它通信方式

除了上面介绍的无名管道和socket通信方式外,一般操作系统中常用的进程间通信机制也都可以用于QT系统内部不同进程之间的通信,如消息队列、共享内存、信号量、有名管道等机制。其中信号量机制在QT中已经重新进行了封装;有些机制则可以直接通过操作系统的系统调用来实现。另外,如果我们只是想通过管道或socket来实现较简单的外部通信,也可以重新创建管道或socket来实现自己要求的功能。例如,还是在QT主程序中调用外部mplayer。如果我们只是想在QT主程序中控制mplayer,而不要求得到mplayer输出的信息。则可以按照以下方式来实现:

1 constchar*mplayerPath = "/mnt/yaffs/mplayer";

2 const char* musicFile = "/mnt/yaffs/music/sound.mp3";

3 const char* arg[5];
4 arg[0] = mplayerPath;

5 arg[1] = "-slave";
6 arg[2] = "-quiet";

7 arg[3] = musicFile;

8 arg[4] = NULL;

9 int fd[2],pid;
10 if(pipe(fd)<0)

11 printf("creating pipe is error\n");

12 else while((pid=fork())<0);

13 if(pid==0)

14 {

15 ::close(fd[1]);

16 ::dup2(fd[0],STDIN_FILENO);

17 execvp(arg[0],(const* char*)arg);

18 }

19 else{

20 ::close(fd[0]);}

18行与前面QProcess类实现调用mplayer一样,是用来指明mplayer运行时参数的。第10行是创建一个管道。第12行是创建一个子进程。1520行是关闭父子进程中没用的管道描述符。此时可结合图2.1和图2.2来理解从父进程到子进程通信环境的建立。第16行是把子进程的读端与标准输入绑定,以便mplayer能够接收到父进程发出的命令。17行就是从子进程中调用外部mplayer的实现。此时,程序执行后,mplayer就可以运行起来。如果想在QT主程序中通过发送命令使mplayer退出,就在管道的写端写入命令"quit"就可以。实现语句为write(fd[1], "quit",strlen("quit"));

该例子说明了QT通信方式运用的灵活性,可以根据实际情况进行应用。同时该例子的实现方式正是利用了QProcess类实现的机制,因此可以结合这个例子更加深刻的理解QProcess类的实现机制。

转自:http://jiani19881.blog.163.com/blog/static/82387541201041202537929/

#include <unistd.h>

int pipe(int fd[2]) ;

返回:若成功则为0,若出错则为-1

分享到:
评论

相关推荐

    Qt进程间通信与同步示例

    总结起来,Qt进程间通信与同步示例通过QFile的内存映射文件实现了高效的数据共享,而QSystemSemaphore则确保了对共享资源的正确同步,避免了潜在的数据冲突。这个示例对于理解Qt中的并发和多进程编程具有重要的实践...

    cop.rar_copserv cel f_qt 进程间通信_qt进程间通信

    标题中的"cop.rar_copserv cel f_qt 进程间通信_qt进程间通信"表明这个压缩包文件包含了一个关于使用Qt库进行进程间通信(IPC,Inter-Process Communication)的示例项目,其中“cop”可能是项目或示例程序的简写,...

    通过Windows窗口消息实现 QT进程间通信

    总之,利用Windows窗口消息进行QT进程间通信是一种实用的技术,它结合了Windows API的强大功能和QT的跨平台特性,为开发者提供了更多选择。不过,在实际项目中,应根据具体需求选择最适合的IPC方法。

    ipc.rar_qt进程间通信

    《QT进程间通信详解》 在软件开发中,进程间通信(IPC,Inter-Process Communication)是一项关键的技术,它使得不同进程之间能够共享数据、协调工作。QT框架为开发者提供了丰富的进程间通信机制,使得在QT应用中...

    QT之进程和进程间通信(IPC)

    进程是操作系统的基础之一。...在 Qt 中,我们使用QProcess来表示一个进程。这个类可以允许我们的应用程序开启一个新的外部程序,并且与这个程序进行通讯。下面我们用一个非常简单的例子开始我们本章有关进程的阐述。

    Qt线程之间通信、线程和进程之间通信实例

    本实例将深入探讨Qt如何实现线程间通信以及线程与进程间通信,并提供简单易懂的代码示例。 一、Qt线程间通信 Qt通过信号和槽机制,使得线程间的通信变得直观且易于理解。信号是对象状态变化的通知,而槽是响应这些...

    三种QT的进程间通信源代码(TCPIP、ShareMemory和Process)

    总结来说,这个资源为学习和研究QT进程间通信提供了宝贵的实践材料。通过学习TCP/IP的网络通信,共享内存的高效数据交换,以及进程通信的控制,开发者能够更好地应对多进程环境下的软件设计挑战。无论是对QT框架的...

    基于dbus的QT进程间通信机制的实现与优化

    Qdebus

    Qt共享内存实现进程间通信(ShareMemory).zip

    Qt共享内存实现进程间通信(QSharedMemory) 源代码

    QT 进程间通信——共享内存-附件资源

    QT 进程间通信——共享内存-附件资源

    Qt进程通信

    关于Qt进程间通信的知识,QT内部对象间通信

    QT的内部进程通信.doc

    虽然目前仅在Qt的嵌入式版本中提供,但它是Qt进程间通信的重要方式之一。QCOP协议依赖于QObject类的子类QCopChannel,它提供了send()和isRegistered()等静态函数来实现通信。接收端需要创建QCopChannel的子类并覆盖...

    Qt Remote Object(QtRO)进程间通信Demo

    Qt Remote Object简称QtRO,这是Qt5.9以后官方推出来的新模块,专门用于进程间通信(IPC)。在这之前,要实现进程间通信有多种方式,这里就不做介绍了,而Qt官方推出的这个新模块是基于Socket来封装的,使用起来非常...

    基于QT的进程间通信,利用共享内存进行图片(Mat格式)传输。调用库opencv。

    在本文中,我们将深入探讨如何使用QT框架进行进程间通信(IPC),特别是在处理图像数据时,如何通过共享内存实现高效的数据传输。我们将结合OpenCV库,以Mat格式的图片为例,来阐述整个过程。 首先,QT是一个跨平台...

    QT进程多个管道通信,并与C#客户端同时多个通信

    QT进程间的多个管道通信以及与C#客户端的并发通信是一个复杂但重要的技术点,尤其在分布式系统和跨平台应用开发中。以下将详细介绍这个主题。 首先,QT是一个强大的跨平台应用程序开发框架,支持多种编程语言,包括...

    QT编写的基于内存共享方式的进程间通信

    在QT中,进程间通信(IPC, Inter-Process Communication)是实现不同进程间数据交换的重要手段,尤其在多进程应用程序中显得尤为重要。本项目"QT编写的基于内存共享方式的进程间通信"着重探讨了利用内存共享作为通信...

    跨平台进程间通信源码

    跨平台进程间通信(IPC,Inter-Process Communication)是计算机技术中的一个重要概念,它允许不同进程之间共享数据、协调工作,实现系统资源的有效利用。在标题中提到的“跨平台进程间通信源码”可能是一个软件库...

    Pipo 的 QT socket的进程间通信

    在QT中,Socket通信是实现进程间通信(IPC, Inter-Process Communication)的一种常见方式,特别是对于Pipo这样的项目,可能涉及到多个进程之间的数据交换。下面将详细介绍QT中的Socket通信以及如何实现进程间通信。...

    【Qt】进程间通信之QSharedMemory程序.rar

    在本文中,我们将深入探讨Qt库中的一个关键特性——QSharedMemory模块,它在进程间通信(IPC,Inter-Process Communication)中扮演着重要角色。QSharedMemory是Qt提供的一种高效且灵活的方式来实现不同进程之间的...

Global site tag (gtag.js) - Google Analytics