1. 程式人生 > >QT程序間通訊詳細介紹及QProcess機制分析

QT程序間通訊詳細介紹及QProcess機制分析

1、QT通訊機制

為了更好的實現QT的資訊互動,在QT系統中建立了較為完善的通訊機制。QT通訊可分為QT內部通訊和外部通訊兩大類。對於這兩類通訊機制及應用場合做如以下分析:

(1)QT內部物件間通訊

在圖形使用者介面程式設計中,經常需要將一個視窗部件的變化通知給視窗的其它部件使其產生相應的變化。對於這種內部物件間的通訊QT主要採用了訊號的機制。這種機制是QT區別於其他GUI工具的核心機制。在大部分的GUI工具中,通常為可能觸發的每種行為通過定義回撥函式來實現。這種回撥函式是一個指向函式的指標,在進行函式回撥執行時不能保證所傳遞的函式引數型別的正確性,因此容易造成程序的崩潰。

    在
QT中,訊號的機制取代了這種繁雜的、易崩潰的物件通訊機制。訊號是當物件狀態改變時所發出的。是用來接收發射的訊號並響應相應事件的類的成員函式。訊號和槽的連線是通過connect()函式來實現的。例如,實現單擊按鈕終止應用程式執行的程式碼 connect(button , SIGNAL(clicked()) , qApp , SLOT(quit()) );實現過程就是一個button被單擊後會激發clicked訊號,通過connect()函式的連線qApp會接收到此訊號並執行槽函式quit()。在此過程中,訊號的發出並不關心什麼樣的物件來接收此訊號,也不關心是否有物件來接收此訊號, 只要物件狀態發生改變此訊號就會發出。此時槽也並不知曉有什麼的訊號與自己相聯絡和是否有訊號與自己聯絡,這樣訊號和槽就真正的實現了程式程式碼的封裝,提 高了程式碼的可重用性。同時,訊號和槽的連線還實現了型別的安全性,如果型別不匹配,它會以警告的方式報告型別錯誤,而不會使系統產生崩潰。

(2)QT與外部裝置間通訊

QT與外部通訊主要是將外部發來的訊息以事件的方式進行接收處理。外部裝置將主要通過socket與QT應用程式進行連線。在此,以輸入裝置與QT應用程式的通訊為例說明QT與外部通訊的原理。

在QT的應用程式開始執行時,主程式將通過函式呼叫來建立並啟動qwsServer伺服器,然後通過socket建立該伺服器與輸入硬體裝置的連 接。伺服器啟動後將會開啟滑鼠與鍵盤裝置,然後將開啟的裝置檔案描述符fd連線到socket上。等到QT應用程式進入主事件迴圈時,事件處理程式將通過 Linux系統的select函式來檢測檔案描述符fd的狀態變化情況以實現對socket的監聽。如果檔案描述符fd狀態改變,說明裝置有資料輸入。此 時,事件處理程式將會發出訊號使裝置輸入的資料能及時得到QT應用程式的響應。資料進入伺服器內部就會以事件的形式將資料放入事件佇列裡,等待QT客戶應 用程式接收處理。處理結束後再將事件放入請求佇列裡,通過伺服器將事件傳送到相應硬體上,完成外部輸入裝置與QT應用程式的整個通訊過程。

2、 QProcess機制分析

QProcess類通常是被用來啟動外部程式,並與它們進行通訊的。QProcess是把外部程序看成是一個有序的I/O裝置,因此可通過 write()函式實現對程序標準輸入的寫操作,通過read(),readLine()和getChar()函式實現對標準輸出的讀操作。

(1) QProcess通訊機制

QT可以通過QProcess類實現前端程式對外部應用程式的呼叫。這個過程的實現首先是將前端執行的程式看成是QT的主程序,然後再通過建立主進 程的子程序來呼叫外部的應用程式。這樣QProcess的通訊機制就抽象為父子程序之間的通訊機制。QProcess在實現父子程序間的通訊過程中是運用 Linux系統的無名管道來實現的,因此為了能更加清楚的說明QProcess的通訊機制,在此首先介紹關於無名管道實現父子程序間的通訊機制。

無名管道是一種只能夠在同族父子之間通訊,並且在通訊過程中,只能從固定的一端寫,從另一端讀的單向的通訊方式。該無名管道是通過呼叫pipe()函式而建立的。建立程式碼如下:

  1. #include <unistd.h>    int pipe(int fd[2]) ;   返回:若成功則為0,若出錯則為-1 

建立後經引數fd返回兩個檔案描述符:fd[0]為讀而開啟,fd[1]為寫而開啟。經過fork()函式建立其子程序後,子程序將擁有與父程序相 同的兩個檔案描述符。如果想要實現父程序向子程序的通訊則關閉父程序的讀端fd[0],同時關閉子程序的寫端fd[1]。這樣就建立了從父程序到子程序的 通訊連線。

由於無名管道的單向通訊性,所以如果要應用無名管道實現父子程序之間的雙向通訊則至少需要應用雙管道進行通訊。QProcess類的通訊原理就是利 用多管道實現了父子程序之間的通訊。然而對於外部執行的應用程式大都是通過標準輸入而讀得資訊,通過標準輸出而傳送出資訊,因此只通過建立管道並不能完成 內外程序?之間的通訊。要解決此問題,就如該模組開始時所說,QProcess是把外部程序看成是一個I/O裝置,然後通過對I/O裝置的讀寫來完成內外 程序的通訊。

在QProcess中父子程序之間是通過管道連線的,要實現子程序能從標準輸入中讀得父程序對管道的寫操作,同時父程序能從管道中讀得子程序對標準 輸出或標準容錯的寫操作,就要在子程序中將管道的讀端描述符複製給標準輸入端,將另外管道的寫端描述符複製給標準輸出端和標準容錯端,即實現管道埠地址 的重定向。這樣子程序對標準輸入、標準輸出及標準容錯的操作就反應到了管道中。

QProcess在正常渠道模式下具體實現共用了五個無名管道進行通訊。五個管道的描述符分別用 childpipe[2],stdinChannelpipe[2],stdoutChannelpipe[2],stderrChannelpipe[2] 和deathpipe[2]五個陣列來儲存。deathpipe指代的管道會用在消亡的子程序與父程序之間。當子程序準備撤銷時會發送一個表示該子程序消 亡的字元給父程序來等待父程序進行處理。stdinChannelpipe,stdoutChannelpipe和stderrChannelpipe所 指代的管道分別與標準輸入,標準輸出和標準容錯進行繫結,實現了與外部程式的通訊。childpipe指代的管道主要是為父子程序之間的通訊而建立的。

如果在管道中有新資料寫入,就會通知相應程序去讀。另外圖2是QProcess在正常渠道模式下的通訊原理圖,如果是在融合渠道模式下,將沒有容錯 管道,此時原理圖中將沒有第一個管道,也就不會有管道描述符。同時,標準容錯端和標準輸出端將共同掛接到子程序的stdoutChannelpipe的寫 端,來實現內外程序的通訊。

(2) QProcess應用方式

由於QProcess類實現了對底層通訊方式較為完善的封裝,因此利用QProcess類將更為方便的實現對外部應用程式的呼叫。在此,通過在QT介面中呼叫外部mplayer的例子來簡單說明QProcess的應用方式。

  1. const QString mplayerPath("/mnt/yaffs/mplayer");    
  1. const QString musicFile("/mnt/yaffs/music/sound.mp3");   
  1. QProcess* mplayerProcess=new QProcess();  
  1. QStringList args;   
  1. args<<"-slave";   
  1. args<<"-quiet";   
  1. args << "-wid"; 
  1. args << 
"-af volume=10"
  1. args<<musicFile;   
  1. mplayerProcess->setProcessChannelMode(QProcess::MergedChannels);  
mplayerProcess->start(mplayerPath,args);  第一行指明瞭所要呼叫的外部應用程式mplayer的位置。 第二行指明瞭所要播放的聲音檔案及目錄路徑。
第三行建立一個指向類QProcess的指標。 第四到第九行指定mplayer引數,具體引數可以檢視maplayer引數介紹 -slave引數表示開啟slave模式. 這用來將MPlayer作為其它程式的後端. MPlayer將從他的標準輸入讀取簡單命令列, 而不再截獲鍵盤事件. SLAVE模式協議部分將解釋其語法 -quiet顯示較少的輸出和狀態資訊 -wid可以為mplayer指定輸出視窗。      -af volume=10選擇輸出音量級別為10.這個選項是不可重入的, 所以對每個音訊流只能使用一次。
    第十行為設定程序渠道的模式為融合模 式,即將標準輸出和標準容錯繫結到同一個管道的寫端。 第十一行為啟動外部應用程式mplayer。核心中管道及通訊環境的建立都是在此步中完成的。
mplayer在slave模式下執行會自動從標準輸入中讀取資訊並執行。由QProcess的通訊原理可知,管道的讀端描述符 stdinChannelpipe[0]複製給了標準輸入,即標準輸入的描述符也為stdinChannelpipe[0],因此按照標準輸入的描述符去 讀資訊就是到stdinChannelpipe所對應的管道中讀取資訊。所以如果想在QT的主程序中傳送命令使mplayer退出,只需在主程式中向 stdinChannelpipe[1]端寫入命令quit就可以,執行語句為myProcess->write(”quit ”);(此處的 write()函式為QProcess類的成員函式,具體實現就是向stdinChannelpipe[1]端寫入資訊)

(3)QProcess的發展及分析

QProcess類伴隨著QT/Embedded的發展逐漸趨於完善。在QTE2及其更前版本中還沒有QProcess類,如果想實現與外部應用程 序的通訊,必須要自己實現對管道或socket的建立與重定向。到了QTE3版本,就實現了對QProcess類的封裝。在QTE3的版本 中,QProcess類的實現是通過應用socket來建立主程序與外部應用程式之間通訊的。通訊原理與圖3所示基本相同,只是將圖中的管道描述符改為是 socket的描述符即可。QT主程式在建立成對socket描述符時需要呼叫Linux系統函式socketpair()。在生成的成對socket描 述符之間可以實現父子程序之間的雙向通訊,即無論是socket的0套介面還是1套介面都可進行讀寫。


但為了避免出現通訊過程中父子程序對同一個socket的爭奪,例如,在子程序還未將父程序傳送的資訊全部讀出時,子程序又要求將自己產生的資料返 回給父程序。如果父子程序雙向通訊只用一個socket來完成,就會出現父子程序傳送的資訊混亂情況。因此,對於QProcess的實現仍然必須通過多個 socket來共同完成。

由上面的描述可知,儘管socket有雙向通訊功能,但在實現QProcess過程中只是利用socket實現了單向通訊功能。因此既浪費了對資源 的利用又增加了系統的開銷。為了解決此問題,QTE4版本將QProcess的通訊連線方式由socket改為了只能實現單向通訊的無名管道來實現。通訊 原理就是以上3.1 QProcess通訊機制中所描述的。

3、其它通訊方式

除了上面介紹的無名管道和socket通訊方式外,一般作業系統中常用的程序通訊機制也都可以用於QT系統內部不同程序之間的通訊,如訊息佇列、共享記憶體、訊號量、有名管道等機制。其中訊號量機制在QT中已經重新進行了封裝;有些機制則可以直接通過作業系統的系統呼叫來實現。另外,如果我們只是想通過管道或socket來實現較簡單的外部通訊,也可以重新建立管道或socket來實現自己要求的功能。例如,還是在QT主程式中呼叫外部mplayer。如果我們只是想在QT主程式中控制mplayer,而不要求得到mplayer輸出的資訊。則可以按照以下方式來實現:

  1.  const char* mplayerPath = "/mnt/yaffs/mplayer";     
  1. const char* musicFile = "/mnt/yaffs/music/sound.mp3";    
  1. const char* arg[5];    
  1. arg[0] = mplayerPath;    
  1. arg[1] = "-slave";    
  1. arg[2] = "-quiet";   
  1. arg[3] = musicFile;   
  1. arg[4] = NULL;   
  1. int fd[2],pid;    
  1. if(pipe(fd)<0)    
  1.     printf("creating pipe is error ");    
  1. else while((pid=fork())<0);    
  1. if(pid==0)    
  1. {    
  1.     ::close(fd[1]);    
  1.     ::dup2(fd[0],STDIN_FILENO);   
  1.     execvp(arg[0],(const* char*)arg);    
  1. }    
  1. else
  1. {  
  1.     ::close(fd[0]);

第1到8行與前面QProcess類實現呼叫mplayer一樣,是用來指明mplayer執行時引數的。第10行是建立一個管道。第12行是建立一個子程序。15,20行是關閉父子程序中沒用的管道描述符。此時可結合圖2.1和圖2.2來理解從父程序到子程序通訊環境的建立。第16行是把子程序的讀端與標準輸入繫結,以便mplayer能夠接收到父程序發出的命令。17行就是從子程序中呼叫外部mplayer的實現。此時,程式執行後,mplayer就可以執行起來。如果想在QT主程式中通過傳送命令使mplayer退出,就在管道的寫端寫入命令"quit"就可以。實現語句為write(fd[1], "quit",strlen("quit"));

該例子說明了QT通訊方式運用的靈活性,可以根據實際情況進行應用。同時該例子的實現方式正是利用了QProcess類實現的機制,因此可以結合這個例子更加深刻的理解QProcess類的實現機制。

相關推薦

QT程序通訊詳細介紹QProcess機制分析

1、QT通訊機制 為了更好的實現QT的資訊互動,在QT系統中建立了較為完善的通訊機制。QT的通訊可分為QT內部通訊和外部通訊兩大類。對於這兩類通訊機制及應用場合做如以下分析: (1)QT內部物件間通訊 在圖形使用者介面程式設計中,經常需要將一個視窗部件的變化通知給

Qt程序通訊(一)--------QProcess

       Qt提供了一個QProcess類用於啟動一個外部程式並與之通訊。啟動一個新程序的操作十分簡單,只需要將待啟動的程式名稱和啟動引數傳遞給start()函式即可。 m_pPro = new

Qt程序通訊——共享記憶體

       Qt提供了一種安全的共享記憶體的實現QSharedMemory,以便在多執行緒和多程序程式設計中安全的使用。比如說QQ的聊天的客戶端,這裡有個個性頭象,當點選QQ音樂播放器的時候,QQ

QT開發(三十五)——QT程序通訊

QT開發(三十五)——QT程序間通訊    Qt 是一個跨平臺的應用框架,其程序間通訊機制當然可以使用所在平臺的程序間通訊機制,如在Windows平臺上的Message機制、共享記憶體、檔案對映、管道、

程序通訊的幾種方式的介紹比較

程序間通訊 就是在不同程序之間傳播或交換資訊,那麼不同程序之間存在著什麼雙方都可以訪問的介質呢?程序的使用者空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享記憶體區。但是,系統空間卻是“公共場所”,所以核心顯然可以提供這樣的條件。除此以外,那就是雙方都可以訪問的外設了。在這個意義上,兩個

QtQt程序通訊QProcess)【轉】

簡述 前幾節裡,分享了程序通訊的幾種方式:Windows訊息機制、Shared Memory(共享記憶體),本節講解下關於程序通訊的另外一種方式-QProcess。 簡述 命令列讀取 說明 實現 更多參考 命令列引數啟動 說明 程序A-帶參啟動

Qt程序通訊QProcess

簡述 QProcess可以在應用程式內部與其它程序通訊,或啟動其它應用程式。與在終端機之類的命令輸入視窗上使用名稱和引數是一樣的,可以使用QProcess提供的函式start()啟動程序。可以註冊QStringList處理程序後的引數。 | 命令列引數啟

php高階應用之程序控制程序通訊

很少有用php寫服務的,然而有些場景又要求能有一個這樣的伺服器程式,它能夠與php無縫結合,並且提供高可靠靠效能的服務,並且提供現有架構所沒有的一些高階特性,例如支援自定義協議,支援長連線等等。PPM(PHP-Process-Manager)是我用PHP開發的一款程序管理

Linux程序相關API程序通訊

一、相關API 1、程序的建立fork()                     #include <unistd.h>                     pid_t fork(void);                     pid_t vfork

Linux環境程序通訊(一) 管道有名管道(轉)

管道是Linux支援的最初Unix IPC形式之一,具有以下特點:管道是半雙工的,資料只能向一個方向流動;需要雙方通訊時,需要建立起兩個管道;只能用於父子程序或者兄弟程序之間(具有親緣關係的程序);單獨構成一種獨立的檔案系統:管道對於管道兩端的程序而言,就是一個檔案,但它不是普通的檔案,它不屬於某種檔案系統,

程序通訊(IPC)介紹

程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。 IPC的方式通常有管道(包括無名管道和命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等。其中 Socket和Streams支援不同主機上的兩個程序IPC。 以Linux中的C

AIDL 程序通訊講解實現步驟

server端的實現1.建立 aidl檔案 (例如ICatl.aidl)2。建立一個server 並在server中建立一個內部類,繼承aidl檔案的stub例如:public class AidlService extends Service { pri

QT程序程序通訊(IPC)

程序是作業系統的基礎之一。一個程序可以認為是一個正在執行的程式。我們可以把程序當做計算機執行時的一個基礎單位。關於程序的討論已經超出了本章的範疇,現在我們假定你是瞭解這個概念的。 在 Qt 中,我們使用QProcess來表示一個程序。這個類可以允許我們的應用程式開啟一個新的外部程式

通訊框架Netty的詳細介紹應用

對於Netty的十一個疑問 【說明】本文原載於碼農 IO(manong.io)官方微信 developerWorks,轉載、引用請註明出處及作者。  1.Netty 是什麼?     Netty 是一個基於 JAVA NIO 類庫的非同步通訊框架,它的架構特點是:非同步非

QtQt程序通訊(Windows訊息)【轉】

簡述 通過上一節的瞭解,我們可以看出程序通訊的方式很多,今天分享下如何利用Windows訊息機制來進行不同程序間的通訊。 效果 傳送訊息 自定義型別與接收窗體 包含所需庫,定義傳送的自定義型別、接收訊息的窗體標題。自定義型別可以處理訊息過多情況下,對訊息的區分,如果不需要也可以去掉。

QtQt程序通訊(共享記憶體)【轉】

簡述 上一節中,我們分享下如何利用Windows訊息機制來進行不同程序間的通訊。但是有很多侷限性,比如:不能跨平臺,而且必須兩個程序同時存在才可以,要麼程序A發了訊息誰接收呢? 下面我們來分享另外一種跨平臺的進行間通訊的方式-Shared Memory(共享記憶體)。 簡述 注意事項

QtQt程序通訊(IPC)【轉】

簡述 程序間通訊,就是在不同程序之間傳播或交換資訊。那麼不同程序之間存在著什麼雙方都可以訪問的介質呢?程序的使用者空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享記憶體區。但是,系統空間卻是“公共場所”,所以核心顯然可以提供這樣的條件。除此以外,那就是雙方都可以訪問的外設了。在這個意義上,兩

【Linux】程序通訊-訊號量詳解程式設計例項

前面一篇文章執行緒同步之訊號量同步 講的是執行緒之間的訊號量,這篇講的更加具有通用性,能夠實現程序之間的同步。 訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛起這

linux記憶體保護機制程序通訊原理

Linux的虛擬儲存器使得每個程序有著統一的、一致的4G地址空間。能支援該功能的主要本質是因為當頁面不在實體記憶體時,由於缺頁異常,將導致異常處理程式從交換空間中把資料換入實體記憶體,然後重新執行導致該異常的指令,而此時就可以正常的訪問,程序本身完全不用去關心該過程。 程序地

程序通訊--訊號量詳解程式設計例項

訊號量概述 訊號量定義: 它是一個特殊變數,只允許對它進行等待和傳送訊號這兩種操作。 P(訊號量變數sv):等待。如果sv大於0,減小sv。如果sv為0,掛起這個程序的執行。V(訊號量變數sv):傳送訊號。如果有程序被掛起等待sv,使其恢復執行。如果沒有進行被掛起等待sv