Linux 程序開發 QT內部進程通信
Linux 程序開發QT內部進程通信的內容是本文要介紹的內容,在Qt 系統中,不僅有著構造完善的系統結構,而且為了滿足用戶對編寫圖形用戶界面應用的種種需求,它還創建了許多新的系統機制,其中Qt 所特有的內部進程通信機制尤其值得一提。本文分析了基于QT 的應用進程之間通信常用的三種機制:QCOP 協議,Signal-Slot 機制和FIFO 機制。給出了各自的使用方法,并指出了各自的使用場合。
1、QCOP協議
QCOP 是Qt 內部的一種通信協議,這種協議用于不同的客戶之間在同一地址空間內部或者不同的進程之間的通信。目前,這種機制還只在Qt 的嵌入式版本中提供。
為實現這種通信機制,Qt 中包括了由QObject 類繼承而來的QCopChannel 類,該類提供了諸如send()、isRegistered() 等靜態函數,它們可以在脫離對象的情況下使用。為了
在channel 中接收通信數據,用戶需要構造一個QCopChannel 的子類并提供receive() 函數的重載函數,或者利用connect() 函數與接收到的信號相聯系。值得一提的是,在Qt 系統中,只提供了QCOP 協議機制和用于接收消息的類,而如何發送消息則沒有提供相應的類供用戶使用。
在基于Qt 的桌面系統Qtopia(QPE)中,則提供了相應的發送類:QCopEnvelope。用戶可以通過該類利用channel 向其他進程發送消息。該類將通過QCopChannel 發送QCop 消息的過程進行了封裝,用戶只需要調用該類中的相關函數就可以方便地實現進程之間的通信過程。一方面,QCop 消息的發送要利用QCopEnvelope 類,另一方面,接收消息則是通過與一個QCopChannel 相關聯。在發送消息時,將利用如下的協議機制:
- QCopEnvelope e(channelname, messagename);
對于需要攜帶參數的消息,必須使用"<<()"運算符將參數添加到envelope 中。
- e << parameter1 << parameter2 << ...;
對于不帶參數的消息,只需要利用:
- QCopEnvelope e(channelname, messagename);
在Qtopia 中,所有的channels 名都以"QPE/"開始,而messagename 則是一個函數的標識符。在接收消息時,通常只需要利用在應用程序中預先定義好的QPE/Application/{appname}管道,當然,也可以根據需要自己定義管道,并將其與一個slot 函數相關聯:
- myChannel = new QCopChannel( "QPE/FooBar", this );;
- connect( myChannel, SIGNAL(received(const QCString &, const QByteArray &)),this,
- SLOT(fooBarMessage( const QCString &, const QByteArray &)) );
下面將具體的通信過程舉例如下,在需要接收消息的類(如Window1)中定義管道:
- QCopChannel *doChannel = new QCopChannel("QPE/Do", this);
- connect(doChannel, SIGNAL(received(const QCString &, const QByteArray &)),
- this, SLOT(doMessage
- (const QCString &, const QByteArray &)));
同時,需要在該類中定義相應的消息處理函數doMessage,
- void Window1::doM essage(const QCString &msg, const QByteArray &args)
- {
- QDataStream stream(args, IO_ReadOnly);
- if(msg == "Message1(QString)")
- {
- QString text;
- stream >> text;
- button->setText(text);
- }
- else if(msg == "Message2()")
- {
- close();
- }
- }
其中的Message1(QString)和Message2(QString)都是用戶自己定義的消息,該函數中分別對這些消息進行了相應的處理。在該例中當收到帶有參數的Message1 消息時,將該字符串參數stream 顯示在按鈕button 上;當收到Message2 消息時,將執行關閉Window1 窗口的動作,當然用戶可以根據需要自行編寫相應的處理過程。
另一方面,在類Class2 中需要發出消息的函數function 中利用QCopEnvelope 發送消息:
- void Class2::function()
- {
- QCopEnvelope e("QPE/Do", "Message1(QString)");
- e << param; }
這里發出了Message1 消息,并將需要攜帶的參數param 發送到管道中。通過這樣的過程,用戶可以很方便地實現不同對象、不同進程之間通信過程,而且可以根據需要在通信過程中任意傳遞參數。
2、信號-槽(Signal-Slot)機制
在Qt 中,有一種用于對象之間的通信:信號-槽機制,這種機制是Qt 的核心機制,也是它區別于其他GUI 工具的最主要的特征。在大多數GUI 工具中,通常為可能觸發的每種
行為定義一個回調函數,這個回調函數是一個指向函數的指針。在Qt 中,信號-槽機制取代這種繁雜的函數指針,能夠實現同樣的功能。信號-槽機制可以攜帶任意類型、任意數量
的參數,而且完全是安全的,不會引起系統的崩潰。
所有由QObject 類繼承而來的類,或者是它的一個子類,都可以包括信號-槽機制。信號通常是當對象改變他們的狀態時發出的,這就是一個對象在需要與其他對象通信時所需要做的一切,它并不知道是否有其他對象在另一端接收該信號。從這個意義上來說,這種機制實現了真正的信息封裝,確保了對象可以被當作一個獨立的軟件構件來使用。
而槽可以被用于接收信號,它們通常是類中的成員函數。一個槽并不知曉是否有一個信號與自己相聯系,同樣,包含有槽函數的對象也對通信機制一無所知,它們也可以作為一個獨立的軟件構件。用戶可以按照需要將許多信號與一個單獨的槽函數相聯系,一個信號也可以按需要被聯系到很多不同的槽函數。甚至還可以將一個信號直接與另一個信號相聯系,這樣當***個信號被發出時立刻發出第二個信號。這樣,信號-槽相結合就產生了一種功能強大的編程機制。
例如:
- button = new QAction(tr("button"), QIconSet(QPixmap("button.png")), 0, 0, this);
- connect(button, SIGNAL(activated()), this, SLOT(slotButton()));
程序中定義了一個按鈕,并利用connect()函數將該按鈕button 的activated()信號與slotButton()函數相關聯,當用戶觸發按鈕時,就會執行相應的槽函數。當然,這里的信號是QAction 類中預先定義好的信號,用戶在使用該機制時,可以根據需要自行定義信號,同時在適當的時候利用emit 語句發出該信號。另外,在信號和相應的槽函數之間還可以傳遞任
意參數,如:
- emit signal(parameter); emit signal(parameter);
3、FIFO 機制
當然,除了Qt 內部所特有的通信機制之外,一般操作系統中常用的進程間通信機制同樣可以用于Qt 系統內部不同進程之間的通信。如消息隊列、共享內存、信號量、管道等機制,其中有些機制,如信號量,在Qt 中重新進行了封裝;有些機制則可以直接調用操作系統的系統調用來實現。這里,有名管道是一種簡單實用的通信機制,用戶在對Qt 內部機制不甚了解的情況下,同樣可以使用這種方法實現對象進程之間的通信。下面就對利用這種機制實現Qt 內部進程之間的通信過程進行介紹。首先,需要創建FIFO,這個過程類似于創建文件,在系統中可以利用mkfifo 命令來創建,這樣就可以用open 函數打開它,同時,一般的文件I/O 函數(close、read、write)都可以用于FIFO。
在基于Qt 的應用中,有很多應用采用了一種客戶機-服務器模式,這時就可以利用FIFO 在客戶機和服務器之間傳遞數據。例如,有一個服務器,它負責接收底層程序發來的消息,同時,它與很多客戶機有關,服務器需要將收到的不同消息發送到不同的客戶機,而每個客戶機也有請求需要發給服務器,進而發給底層程序。
下面是服務器端的程序示例:(架設已有客戶端進程為讀而打開/dev/fifoclient1 和
- /dev/fifoclient1)
- fd = open("/dev/fifoserver", O_NONBLOCK|O_RDONLY);
- file = fdopen(fd, "r");
- ret = fgets(buf, MAX_LINE, file );
- if(buf[0] == '0')
- {
- QFile fd_file("/dev/fifoclient1");
- QString temp(buf);
- if(fd_file.open(IO_WriteOnly|IO_Append)) {
- QTextStream t(&fd_file);
- t<< temp;
- fd_file.close();
- }
- else if(buf[0] == '1')
- {
- QFile fd_file("/dev/fifoclient2");
- QString temp(buf);
- if(fd_file.open(IO_WriteOnly|IO_Append)) {
- QTextStream t(&fd_file);
- t<< temp;
- fd_file.close();
- }
- ……
在該程序中,服務器接收底層發來的信息(這里假設也是由FIFO 管道傳來),然后根據收到的信息內容,如***個字節的內容,將信息發到不同客戶端的管道中,實現對信息的
正確分發。
客戶端程序示例如下:(假設服務器端已經為讀而打開/dev/fifo 管道)
- QFile out_file("/dev/fifo");
- if(out_file.open(IO_WriteOnly|IO_Append)) {
- QTextStream t(&out_file);
- t << text << "\n"; }
小結:Linux 程序開發 QT內部進程通信的內容介紹完了,希望本篇文章能夠幫助你有效學習,剛鐸內容參考編輯推薦吧!