王惠軍
(山西大眾電子信息產(chǎn)業(yè)集團(tuán)有限公司,山西 太原 030024)
Qt是一個(gè)1991年由Qt Company開發(fā)的跨平臺(tái)C++圖形用戶界面應(yīng)用程序開發(fā)框架。它既可以開發(fā)GUI程序,也可用于開發(fā)非GUI程序,比如控制臺(tái)工具和服務(wù)器。QT支持Windows、Unix、Android、iOS等多種操作系統(tǒng),具有優(yōu)良的跨平臺(tái)特性。Qt具有良好封裝機(jī)制,使得Qt的模塊化程度非常高,可重用性較好,各個(gè)元件之間的協(xié)同工作變得十分簡單。QT還包含豐富的API,包括多達(dá)250個(gè)以上的C++類,還提供基于模板的Date/Time、Serialization、File、Collections、I/O device、Directory management類?;谝陨螿t的眾多優(yōu)點(diǎn),使用QT開發(fā)程序會(huì)更加的方便、高效、簡單。下邊就介紹如何在Windows操作系統(tǒng)下,通過QT實(shí)現(xiàn)進(jìn)程間的通信。
首先介紹QT的開發(fā)和運(yùn)行環(huán)境。操作系統(tǒng)選擇Win7 64位,QT版本為5.0.2,C編譯器版本:VS2010,調(diào)試工具為Windbg,設(shè)置好的系統(tǒng)環(huán)境變量包含C:QtQt5.0.2·.0.2msvc2010_openglin、C:WindowsSystem32、C:Program Files (x86)Microsoft Visual Studio 10.0VCin、C:Program Files (x86)Microsoft Visual Studio 10.0Common7IDE。
基于QT開發(fā)程序,可通過消息隊(duì)列、信號(hào)、共享內(nèi)存、套接字等方法實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)通信。本文主要介紹如何通過套接字和共享內(nèi)存相結(jié)合的方法實(shí)現(xiàn)進(jìn)程間的通信。
設(shè)計(jì)思路如圖1所示。建立兩個(gè)應(yīng)用程序,在程序中分別開辟相同的共享內(nèi)存,建立套接字,共享內(nèi)存用來保存數(shù)據(jù),套接字用來發(fā)送和接收數(shù)據(jù)已更改的消息。在第一個(gè)程序中輸入數(shù)據(jù),數(shù)據(jù)變化后,修改共享內(nèi)存中內(nèi)容,同時(shí)向第二個(gè)程序發(fā)送數(shù)據(jù)已更改的消息,第二個(gè)程序收到數(shù)據(jù)已更改的消息后,在共享內(nèi)存中讀取最新的數(shù)據(jù),并顯示在界面上。
圖1 設(shè)計(jì)思路
首先介紹第一個(gè)程序(T1)的實(shí)現(xiàn)方法。
1) 在QT Creator中新建Qt Gui應(yīng)用程序,在名稱編輯框中輸入T1,其它默認(rèn)。
2) 添加輸入界面。在界面中添加“LineEdit”控件,添加槽textEditChange(),用來接收輸入變化的消息。
3) 修改頭文件。添加的內(nèi)容見表1。
表1 頭文件mainwindow.h
第1行和第2行分別包含了頭文件“QSharedMemory”、“QtNetwork/QUdpSocket”,其中加載QSharedMemory表示可調(diào)用共享內(nèi)存的函數(shù),加載QtNetwork/QUdpSocket表示可調(diào)用套接字的函數(shù)。
第5行到第7行定義了與共享內(nèi)存有關(guān)的變量和函數(shù)。
第8行到10行定義了與套接字有關(guān)的變量和函數(shù)。
第12行定義了槽,用來接收數(shù)據(jù)變化的消息。
4) 修改CPP文件。在mainwindow.cpp中,需要對(duì)CreateShareMem函數(shù)、initSocket函數(shù)、TextEditChanged函數(shù)進(jìn)行修改。
修改結(jié)果見表2。
第1行為共享內(nèi)存指針分配了地址;第2行設(shè)置了共享內(nèi)存的關(guān)鍵字;第3行將共享內(nèi)存與本程序解綁,保證其它進(jìn)程也可訪問該共享內(nèi)存;第4行設(shè)置共享內(nèi)存的大小。
第5行用來創(chuàng)建套接字,給套接字指針分配地址;第6行用來綁定IP地址和端口號(hào),綁定的IP地址是本機(jī)地址,端口號(hào)是7755。
第7行和第8行用來判斷共享內(nèi)存指針是否與本進(jìn)程綁定;第9行將共享內(nèi)存的數(shù)據(jù)鎖定;第10行得到共享內(nèi)存的大??;第11行得到界面中輸入的數(shù)據(jù);第12行得到界面輸入數(shù)據(jù)的長度;第13行將共享內(nèi)存的大小與數(shù)據(jù)長度進(jìn)行比較,保證寫到共享內(nèi)存中的數(shù)據(jù)不會(huì)溢出;第14行將界面中的數(shù)據(jù)復(fù)制到共享內(nèi)存中;第15行將共享內(nèi)存的數(shù)據(jù)解鎖,保證其它進(jìn)程可以讀取共享內(nèi)存中的數(shù)據(jù);第16行調(diào)用發(fā)送套接字消息的函數(shù),將數(shù)據(jù)已更改的消息發(fā)送到第二個(gè)程序。
表2 修改結(jié)果
經(jīng)過以上過程,第一個(gè)程序就完成了,接下來介紹第二個(gè)程序(T2)的實(shí)現(xiàn)方法。
T2項(xiàng)目的創(chuàng)建方法與T1項(xiàng)目的創(chuàng)建類似,在名稱編輯框中輸入T2,其它設(shè)置與T1項(xiàng)目一致。
1) 添加輸入界面。在界面中添加“LineEdit”控件,添加信號(hào)signal_TextChanged(QString)。在信號(hào)和槽編輯器中添加連接,發(fā)送者是MainWindow,信號(hào)是signal_TextChanged(QString),接收者是LineEdit,槽是SetText(QString)。
2) 修改頭文件。T2項(xiàng)目的頭文件與表1的內(nèi)容類似。
3) 修改CPP文件。在mainwindow.cpp中,需要對(duì)CreateShareMem函數(shù)、initSocket函數(shù)、readPendingDatagrams函數(shù)進(jìn)行修改,其中CreateShareMem函數(shù)與T1項(xiàng)目的內(nèi)容完全一致,initSocket函數(shù)中,綁定的端口號(hào)為7756,同時(shí)添加信號(hào)連接,用來響應(yīng)套接字收到數(shù)據(jù)的消息。
修改結(jié)果見表3。
表3 readPendingDatagrams函數(shù)修改結(jié)果
第1行到第5行定義了函數(shù)中需要用到的變量,包括套接字的數(shù)據(jù)、地址、端口號(hào),共享內(nèi)存的數(shù)據(jù);第6行判斷套接字是否收到數(shù)據(jù);第7行通過套接字指針讀取收到的消息,同時(shí)返回消息的內(nèi)容、長度、IP地址和端口號(hào);第8行到第13行表示從共享內(nèi)存中讀取數(shù)據(jù),與表7中第1行到第9行的含義一致;第14行將最新的數(shù)據(jù)通過信號(hào)發(fā)送給LineEdit控件。
經(jīng)過以上過程,第二個(gè)程序就完成了。
分別對(duì)兩個(gè)程序進(jìn)行編譯,編譯成功后運(yùn)行T1.exe和T2.exe,在T1中輸入信息后,T2會(huì)同步進(jìn)行顯示,如圖2所示。
圖2 運(yùn)行結(jié)果
本文通過一個(gè)簡單的例子實(shí)現(xiàn)了進(jìn)程間數(shù)據(jù)的通信,通過套接字與共享內(nèi)存結(jié)合的方式,可實(shí)現(xiàn)不同進(jìn)程間數(shù)據(jù)的實(shí)時(shí)同步,通過改變套接字的消息類型,可實(shí)現(xiàn)不同種類數(shù)據(jù)的同步,在工程應(yīng)用中有重要的意義。