1. 程式人生 > >Qt和C語言之間的互動

Qt和C語言之間的互動

轉自:http://blog.csdn.net/fengel_cs/article/details/46894605

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類的實現機制。

相關推薦

QtC語言之間互動

轉自:http://blog.csdn.net/fengel_cs/article/details/46894605 1、QT通訊機制 為了更好的實現QT的資訊互動,在QT系統中建立了較為完善的通訊機制。QT的通訊可分為QT內部通訊和外部通訊兩大類。對於這兩類通訊機制

C#與C++C語言之間資料型別的對應

一、C#與C++資料型別的對應表  

lua C 語言進行互動 —— 如何傳遞table

方法1: 採用 lua_pushstring/lua_pushnumber 傳遞key、value,然後通過 lua_settable 設定 table 中的kv對,like this: lua_pushnumber(L, 1); lua_pu

淺析c++c語言的enum類型

gre gree 但是 最大 src 淺析 end cnblogs () 1.先看c語言枚舉類型 1.c語言定義枚舉類型,每一個枚舉元素都是一個整數2.註重數據類型,沒有數據類型限定3.相鄰枚舉元素相差整數4.可以通過整數訪問,不夠安全 2.上代碼: 1 #includ

201671010139 2016-2017-2 JAVA C語言的語法區別

tro 特點 建立 優點 cor ext 虛函數 ref strong   java和c語言的語法上有很多相似的地方,但也有很多不同。 一,在初始值的區別   在C語言中,是可以不初始化使用的   而在JAVA中,是必須初始化值的 二,在抽象方法或抽象類的區別   C語言的

Java 自增(++) C語言中自增的區別

%d 區別 但是 [] .cn cnblogs 微軟雅黑 自增 華麗 在Java、c語言等高級語言中自增和自減的作用基本一致,都是變量自身加一或減一。下面我只對自增進行說明,自減是類似的。 自增運算符(++),有兩種書寫形式,一個是在變量前: ++ num; 另一種

VC++C語言中常見數據類型轉換為字符串的方法

char* 北京 相同 字符指針 ascii bst sdn sprint 出現 1。短整型(int) itoa(i,temp,10);///將i轉換為字符串放入temp中,最後一個數字表示十進制 itoa(i,temp,2); ///按二進制方式轉換 2。長整型(long

20165231 預備作業二:學習基礎C語言基礎調查

oid clu 百度知道 保持 運行 建議 內聚 理解 加減乘除 微信文章感想 讀了婁老師微信公眾號中的文章,老師給我們的啟示首先就是要堅持,萬事開頭難,但是只要肯堅持就一定會有所成就,不管是學習還是生活方面。其中最有觸動的就是減肥了,是我三四年來一直難以完成的目標。如果可

20165303學習基礎C語言基礎調查

過程 度量 弱點 指針 計算 指針數組 數組指針 服務 發生 20165303學習基礎和C語言基礎調查 技能學習心得 我認為我的乒乓球打的還不錯,不能說非常好,但是基本的一些技巧都還是會的,小時候爸爸就非常愛看乒乓球比賽,有時候也帶著我一起看,最開始看的時候我發現激烈的比

20165339 學習基礎c語言基礎調查

指針函數 理論 引用 程序 可能 關系 知識點 比較 方法 讀中學讀後感 我認為給學生具體的, 能實踐的, 能馬上看到因果關系的教材和練習, 是激發學生興趣, 好奇心, 求知欲的好方法。 我就是這樣學習編程和軟件開發的。 所以我對「習而學」的方法很有好感。軟件工程有理論的

20165220 學習基礎C語言基礎調查

函數指針 void 內心 迷茫 開始 學習 模板 我們 scanf # # # # 我覺得我打遊戲(不知道算不算一技之長)畢竟從小學一年級就接觸到了各種形形色色的遊戲,講道理其實我的遊戲天賦畢竟還是很大的,從意識到感覺我覺得都比大多數人好一些,其實吧打遊戲打得好也是很不容易

20165235 學習基礎C語言基礎調查

mys 文本文 cnblogs 教材 getchar eof 學習 都是 file 20165235 學習基礎和C語言基礎調查 首先第一個問題:你有什麽技能比大多人(超過90%以上)更好?感覺很難回答這種問題,其實我對很多東西挺感興趣的,如果非要拿出一種比較突出的技能的話

20165218 學習基礎C語言基礎調查

結構 打印數組 打印 編程語言 緩沖 讓我 質變 存在 返回值 個人技能及閱讀心得 個人技能之繪畫 繪畫是我從很小便開始接觸的,從最初的簡筆畫到國畫、素描、水粉,大約也學了七八年。但是到了高中之後,就逐漸放下了。 記得當初學素描時,老師的一句話讓我記憶猶新,她說,畫素描

20165212 學習基礎C語言基礎調查

不足 代碼 編寫 是我 語句 解釋 靠譜 信息 main 學習基礎與C語言基礎調查 閱讀文章的心得體會 五篇文章都從不同角度闡述了毅力的重要性,打字、減肥、運動各方面,比如“每天一萬步”這個任務,人們通過建群聊互相監督、“打卡”的方式來實現堅持的目的,我認為這很愚蠢

20165310 學習基礎C語言基礎調查

直接 查找 而是 string 程序編寫 出錯 sys reader erb 學習基礎和C語言基礎調查 做中學體會 閱讀做中學之後,了解老師關於五筆練習、減肥、乒乓和背單詞的經歷,不禁聯想到自己學古箏的經歷。 成功的經驗 興趣 我其實小時候學過一段時間古箏,但是那時候是

20165318 預備作業二 學習基礎C語言基礎調查

第六章 post 教學 風雨無阻 但是 隨著 文本文件 快速 學習經驗 20165318 學習基礎和C語言基礎調查 技能學習經驗 我們這一代人,或多或少的都上過各種興趣班,舞蹈鋼琴畫畫書法,我也是如此。可這些技能中,唯一能拿的出手的就是舞蹈了。按照《優秀的教學方法---做教

學習基礎C語言基礎調查

求學 false pos 超過 只需要 多個 每天 通過 ber 學習基礎和C語言基礎調查 一、一種比大多數人(超過90%以上)更好的技能 說句實話,我還沒有那種特別特別自信的、說我能拿得出手的、所謂能超過百分之九十以上的人的技能。畢竟人外有人,天外有天。 姑且算上象棋吧,

20165323 學習基礎C語言基礎調查

每天 繪制 調用 gpo 重要 高質量 數組指針 平衡 是否 20165323 學習基礎和C語言基礎調查 一、技能學習心得 1、你有什麽技能比大多人更好? 我覺得我羽毛球打的還行,不能說打得比大多數人好,但是對於一些打羽毛球的要領還是掌握的。 2、針對這個技能的獲取你有什麽

20165210 學習基礎C語言基礎調查

內聚 div 數組的指針 item 是我 作業 .cn ref 進程 20165210 學習基礎和C語言基礎調查 一、技能學習過程和心得 讀了婁老師《做中學》自己還是深有感受的,對於運動、音樂、棋牌都會一點,我覺得做中學可以概括為三點:做,學,學做結合,所謂的做就是實踐,反

20165331 學習基礎C語言基礎調查

提高 logs scan 解決問題 {0} 想去 難度 trac 例子 學習基礎和C語言基礎調查 你有什麽技能比大多人(超過90%以上)更好? 看到題目,我陷入了迷茫:我到底有什麽方面可以做的比90%的人更好呢。思來想去,可能是動手能力這一方面吧。小時候我就很喜歡對玩具進行