1. 程式人生 > >glib學習筆記之三——GLib核心應用支援:glib 中 IO Channels 理解

glib學習筆記之三——GLib核心應用支援:glib 中 IO Channels 理解

原文連結

GUI系統都是基於事件驅動的,其中必有一個事件迴圈過程來獲取和處理事件。gtk也一樣,gtk的事件迴圈過程是由glib提供的,而iochannel是glib中把IO事件整合到事件的一種手段。

iochannel可以把開發者指定的發生在 檔案描述符、管道和socket之上的事件轉換為glib的內部事件,從而可以在程式中用統一的方法來處理IO事件和使用者互動。

iochannel支援的IO事件有 可讀、可寫、有緊急(urgent)資料到達、出錯、結束通話。由於iochannel是在 檔案描述符、管道和socket 的基礎上構建的,所以它提供的方法既包括這三者的共同點,也考慮到了這三者的不同之處。


那麼怎樣在基於gtk或者glib的程式中加入iochannel呢?

步驟一般為:

1. 建立一個檔案描述符。

可以通過開啟一個普通檔案、建立管道或者開啟socket來實現,結果都是得到一個檔案描述符。

2. 建立iochannel,設定資料編碼。

iochannel通過如下函式建立:

GIOChannel* g_io_channel_unix_new (int fd);

例如:

io_channel = g_io_channel_unix_new (fd);

建立之後可以設定資料編碼。對於資料編碼,我也不太明,一般我把編碼設定為NULL,這樣在使用iochannel提供的讀寫函式時就不會對資料進行任何處理。編碼設定函式如下:

GIOStatus g_io_channel_set_encoding (GIOChannel *channel, const gchar *encoding, GError **error);

例如,把編碼設定為NULL:

g_io_channel_set_encoding (io_channel, NULL, &err);

3. 把你所需要處理的發生檔案描述符上的事件加到事件迴圈中。

通過如下函式把iochannel的指定事件加入到事件迴圈中:

guint g_io_add_watch (GIOChannel *channel, GIOCondition condition, GIOFunc func, gpointer user_data);

其中,GIOCondition包括G_IO_IN, G_IO_OUT, G_IO_PRI,G_IO_ERR, G_IO_HUP, G_IO_NVAL。可以通過對它們的或運算來同時指定多個事件,當然回撥函式應該判斷是哪個的事件引起回撥。

iochannel的回撥函式原型為:

gboolean (*GIOFunc) (GIOChannel *source, GIOCondition condition, gpointer data);

第二個引數便是引起回撥的事件的值。




上面第1步的作用就好比建立一個按鈕,而第2,3步的作用就好比用g_signal_connect()把一個事件加入事件迴圈。做好這3個工作,後面還有兩個工作:

1. 編寫回調函式。

在回撥函式中,你可以採用iochannel提供的讀寫函式,也可以用g_io_channel_unix_get_fd()獲得的檔案描述符來進行平常的IO操作。

2. 退出事件迴圈,關閉iochannel。

在程式結束,或者檔案描述符已經沒用的時候,應該關閉iochannel。在關閉前必須先退出事件迴圈,用g_source_remove(source_id)完成退出動作。source_id是g_io_add_watch()的返回值。

跟著便可以關閉iochannel了,用g_io_channel_shutdown (io_channel, TRUE, NULL)來完成關閉動作。

關閉後iochannel所佔記憶體還沒有釋放,用g_io_channel_unref (io_channel)來減少iochannel的參考計數器,使其為0,glib會自動釋放該iochannel。



根據你的應用,我的建議是在連線到伺服器之後利用socket的檔案描述符建立iochannel,並且為除 資料可寫(G_IO_OUT)外的其他事件都建立回撥函式,加入事件迴圈。當有資料來時被動讀取,傳送資料時主動傳送。


一個iochannel只能繫結一個socket。

伺服器那端,用listen之後的fd (設為listen_fd) 建立一個iochannel。

當有連線來時,iochannel表現為listen_fd可讀。在回撥函式中accept,得到一個連線fd(設為connect_fd)。然後為每一個connect_fd建立一個iochannel。

簡單的說就是listen_fd的回撥函式是accept用的;connect_fd的回撥函式是讀寫用的,每個connect_fd的回撥函式都一樣。

connect_fd關閉後關閉該iochannel。

關於關閉iochannel,可能要用g_idle_add()新增一個垃圾回收函式。

因為不能在connect_fd的回撥函式中shutdown該iochannel。

客戶端要注意connect的超時時間比較長,可能需要用到執行緒來解決這個問題。

想實現“在按鍵事件開始後不斷的讀串列埠,直到關斷串列埠的按鍵事件啟動”的話,用while是不可行的,單單加入非阻塞也不行,因為在while迴圈中你的程式將不會響應按鍵事件。

多執行緒是可以解決問題的,不過儘量不要使用。



用iochannel是最合適的。方法大致如下:



1. 以非阻塞方式開啟串列埠,非阻塞是必須的,下面會提到原因。

fd = open("/dev/ttyS0",O_RDWR|O_NONBLOCK,0644);



2. 建立iochannel。

io_channel = g_io_channel_unix_new (fd);

g_io_channel_set_encoding (io_channel, NULL, &err); /* 應該可選 */



3. 把檔案描述符可讀的事件加入到程式的事件迴圈中:

source_id = g_io_add_watch (io_channel, G_IO_IN, read_ttyS, NULL);



4. 當這些做好後就可以用 read_ttyS() 來讀取串列埠資料了。

你可以用 read() 來直接讀串列埠資料,也可以用 glib 提供的iochannel讀取函式讀。

不過要注意的是必須要用迴圈讀到出現沒有資料可讀以致返回錯誤時才能結束一次讀操作。這是因為核心中有緩衝,要是一次讀取沒有把全部資料讀完的話,本應該
在這次回撥中讀取的資料就要等到下一次才能讀取了。串列埠的資料流量不大,不用這種處理辦法可能也不會有問題,不過還是保險一點好。上面開啟串列埠時使用非阻
塞方式就是為了這裡可以把達到的資料完整讀完。



5. 當停止讀取的事件發生時,回撥函式應該做如下工作:

* (1). 退出事件迴圈: g_source_remove (source_id);

* (2). 關閉 IO_Channel: g_io_channel_shutdown (io_channel, TRUE, NULL);

* (3). 釋放 IO_Channel: g_io_channel_unref (io_channel);

關閉 iochannel 操作會把檔案描述符關閉。



6. 其他:

開啟和關閉 iochannel 的順序不可變。

要是隻想暫時不讀檔案妙算符,可以只退出事件迴圈。

不保證退出事件迴圈後到來的資料是否會在核心中快取,不保證這段時間內的資料是否全部被快取,所以當你退出事件迴圈再加入時要自己檢查資料是否是你所需要的。(不保證是因為我沒有做過試驗)

iochannel不是什麼新技術,它的基礎是 select / poll,對比一下 g_io_add_watch 提供的事件選項和
select / poll 提供的就清楚了。關於 select / poll 請 man 2 select_tut或者 man 2 poll。

上面提到的方法對其他檔案描述符都適用,我之前是把它用在socket上。

相關推薦

glib學習筆記——GLib核心應用支援glib IO Channels 理解

原文連結 GUI系統都是基於事件驅動的,其中必有一個事件迴圈過程來獲取和處理事件。gtk也一樣,gtk的事件迴圈過程是由glib提供的,而iochannel是glib中把IO事件整合到事件的一種手段。 iochannel可以把開發者指定的發生在 檔案描述符、管道和socke

【Java學習筆記十二】淺談Javathrow與throws的用法及異常拋出處理機制剖析

input auto void ref 淺談 .html ssa 不能 而是 異常處理機制 異常處理是對可能出現的異常進行處理,以防止程序遇到異常時被卡死,處於一直等待,或死循環。 異常有兩個過程,一個是拋出異常;一個是捕捉異常。 拋出異常 拋出異常有三種

glib學習筆記二(續)——GLib核心應用支援The Main Event Loop

原文地址 描述 The main event loop manages all the available sources of events for GLib and GTK+ applications. These events can come from any n

學習筆記《Java核心技術卷I》---- 第章 Java的基本程式設計結構

Java中沒unsigned關鍵字 int Math.round(float a)  long Math.round(double a) &&、||:短路操作   &、|:非短路操作 列舉型別必須放在放在函式之外定義

Linux學習筆記————Linux命令概述

上下 eight ive 幫助 option pos misc tor tro 一、引言 很多人可能在電視或電影中看到過類似的場景,黑客面對一個黑色的屏幕,上面飄著密密麻麻的字符,梆梆一頓敲,就完成了竊取資料的任務。 Linux 剛出世時沒有什麽圖形界面,所有的操

dbms_lob包學習筆記instr和substr存儲過程

hello 字節數 TE bms HERE substring 成功 其中 oracle instr和substr存儲過程,分析內部大對象的內容 instr函數與substr函數 instr函數用於從指定的位置開始,從大型對象中查找第N個與模式匹配

R語言學習筆記

結構 urn padding 效果 rand html 創建 字符 pri 僅用於記錄R語言學習過程: 內容提要:條件與循環 正文: 格式: 條件 ü if (條件) 執行的程序 else ü if (條件) {函數體 (分行,或者用;隔開) } else 返回值 ü

C++學習筆記

() 利用 在一起 忘記 構造函數 end 會同 筆記 允許 9.3.3為何所有的析構函數都應該聲明為 virtual 的?如果使用delete刪去一個實際指向派生類的基類指針,析構函數調用鏈就被破壞。這導致後面使用parent 的指針訪問child 對象並刪去對象時,就

Memcached學習筆記詳解MemCached原理

memcached是一個高效能的分散式記憶體快取伺服器,memcached在Linux上可以通過yum命令安裝,這樣方便很多,在生產環境下建議用Linux系統,memcached使用libevent這個庫在Linux系統上才能發揮它的高效能。它的分散式其實在服務端是不具有分散式的特徵的,是依靠客戶端

Vue.js框架學習筆記

Vue.js中的表單 可以用v-model指令在表單 <input>及 <textarea>元素上建立雙向資料繫結,它會根據控制元件型別自動選取正確的方法來更新元素。 v-model 會忽略所有表單元素的 value、checked、select

ElasticSearch學習筆記十二 JAVA Client Exists Delete Update APIs

ElasticSearch學習筆記之三十二 JAVA Client 之 Exists Delete Update APIs Exists API Exists Request Synchronous Execution(同步執行) Asy

ElasticSearch學習筆記十一 JAVA Client GET APIs

ElasticSearch學習筆記之三十一 JAVA Client 之 GET APIs Get API Get Request Optional arguments(引數配置) Synchronous Execution(同步執行)

ElasticSearch學習筆記十 JAVA Client Document APIs

ElasticSearch學習筆記之三十 JAVA Client 之 文件請求概述 Document APIs(文件APIS) Index API Index Request(索引請求) Providing the document sou

ElasticSearch學習筆記十三 IK分詞器擴充套件字典及text全文型別資料分詞聚合查詢

ElasticSearch學習筆記之三十三 IK分詞器擴充套件字典及text全文型別資料分詞聚合查詢 專屬詞彙分詞失敗 擴充套件字典 檢視當前詞庫 自定義詞典 更新配置 再次檢視分詞 text全文型別資料分詞聚合

MyBatis學習筆記--關聯關係(多對多)

MyBatis學習筆記(三) 關聯關係 首先給大家推薦幾個網頁: http://blog.csdn.net/isea533/article/category/2092001 沒事看看 - MyBatis工具:www.mybatis.tk http://www.mybatis.o

SpringSecurity學習筆記配置使用者儲存

沒有使用者儲存的應用相當於沒有使用者,因為任何使用者都會被拒之門外。我們所需要的是使用者儲存,也就是使用者名稱、密碼以及其他資訊儲存的地方,在進行認證決策的時候,會對其進行檢索。Spring Security非常靈活,能夠基於各種資料儲存來認證使用者。它內建了多種常見的使用者

學習筆記《Java核心技術卷I》---- 第八章 泛型程式設計

泛型類的定義格式:class Pair<T>{ } 普通類中泛型方法的定義:public static <T> T getMiddle(T... a){ return a[a.length / 2]; } 呼叫方法時,可以使用:ClassName.getMi

學習筆記《Java核心技術卷I》---- 第七章 異常、斷言和日誌

異常物件都是派生與Throwable的一個例項 派生於Error類或RuntimeException類的所有異常稱為非受查異常,所有其他異常稱為受查異常 一個方法必須宣告所有可能丟擲的受查異常,而非受查異常要麼不可控制,要麼就應該避免發生 關鍵字throws位於方法之

學習筆記《Java核心技術卷I》---- 第六章 介面、lambda表示式與內部類

介面中的所有方法都自動地屬於public。因此,在介面中宣告方法時,不必提供關鍵字public;但是在實現介面的類中,必須在實現介面中的方法時把介面中的方法宣告為public,如果不宣告,那就預設包訪問許可權,編譯器會報錯 實現Comparabale介面,必須實現其中的compareTo

學習筆記《Java核心技術卷I》---- 第五章 繼承

Java中所有繼承都是公有繼承 this是當前物件的引用,而super不是一個物件的引用,不能將super賦給另一個物件變數,它只是一個指示編譯器呼叫超類方法的特殊關鍵字 /* 以下程式碼可以成功編譯執行 */ class Employee{ private String na