你好,歡迎來到IOS教程網

OSX

編輯:IOS開發基礎

在OSX/iOS中IO多路復用通常會選擇select和kqueue,最近在嘗試優化socket改進通信效率,所以總結一下兩種模型的用法。

select

select是socket編程中非常重要的一個函數,並且也是兼容性最好的一種模型,在unix、linux、windows都有對應的實現,其函數原型是:

int select(
  int nfds,
  fd_set* readfds,
  fd_set* writefds,
  fd_set* errorfds,
  const struct timeval* timeout
);

nfds最大的文件描述符加1;

readfds:用於檢查可讀性的描述符集合,同時也是可讀描述符的結果返回;

writefds:用於檢查可寫性的描述符集合,同時也是可寫描述符的結果返回;

errorfds:用於檢查異常的描述符集合,同時也是異常描述符的結果返回;

timeout:一個指向timeval結構的指針,用於決定select等待I/O的最長時間,它可以使select處於三種狀態:

(1)第一,若將NULL以形參傳入,即不傳入時間結構,就是將select置於阻塞狀態,一定等到監視文件描述符集合中某個文件描述符發生變化為止;

(2)第二,若將時間值設為0秒0毫秒,就變成一個純粹的非阻塞函數,不管文件描述符是否有變化,都立刻返回繼續執行,文件無變化返回0,有變化返回一個正值;

(3)第三,timeout的值大於0,這就是等待的超時時間,即 select在timeout時間內阻塞,超時時間之內有事件到來就返回了,否則在超時後不管怎樣一定返回,>返回值同上述。

函數返回值:

負值:select錯誤

正值:某些文件可讀寫或出錯

零值:等待超時,沒有可讀寫或錯誤的文件

kqueue

kqueue是FreeBSD上的一種的多路復用機制,所以剛好能在OSX/iOS中使用。它是針對傳統的select處理大量的文件描述符性能較低效而開發出來的。注冊一批描述符>到kqueue以後,當其中的描述符狀態發生變化時,kqueue將一次性通知應用程序哪些描述符可讀、可寫或出錯了.

kqueue模型最主要的函數就是kevent,它與select類似,提供向內核注冊/反注冊/修改事件和返回就緒事件或錯誤事件,函數原型為:

int kevent(
  int kq,
  const struct kevent *changelist,
  int nchanges,
  struct kevent *eventlist,
  int nevents,
  const struct timespec *timeout
);

kq:由kqueue()返回的一個內核事件隊列標識;

changelist:注冊/反注冊事件的列表;

nchanges:changelist的個數;

eventlist:用於返回有事件發生的列表;

nevents:傳入的eventlist的最大長度;

timeout:一個指向timeval結構的指針,指定超時時間;

函數返回值與select類似。

另外比較重要的就是struct kevent這個結構體了,它既是注冊、反注冊、修改事件的載體,也是事件返回的載體,它的原型為:

struct kevent {
  uintptr_t       ident;
  short           filter;
  u_short         flags;
  u_int           fflags;
  intptr_t        data;
  void            *udata;
};

由於kqueue不僅僅用於socket,還可用於如文件狀態、信號、進程等用途,以下僅僅當在網絡編程時這些元素的值及含義:

ident:事件的id,實際應用中,一般設置為文件描述符;

filter:指定你希望內核用於ident成員的過濾器,我們可以指定EVFILT_READ(讀狀態)和EVFILT_READ(寫狀態);

flags:告訴內核應當對該事件在隊列做何處理,我們可以指定EV_ADD(注冊)、EV_DELETE(刪除)、EV_ENABLE(開啟,默認)、EV_DISABLE(停用),當flags用於eventlist返回事件時,可能包含EV_ERROR的掩碼表示描述符錯誤事情;

fflags:用於指定你想讓內核使用的特定於過濾器的標志;

data:用於保存任何特定於過濾器的數據,當filter指定為EVFILT_READ或EVFILT_READ時,data表示可讀或可寫的數據長度,當事件的描述符出錯時,data表示錯誤>代碼;

udata:data成員並不由kqueue使用,kqueue會把它的值不加修改地透傳,用於類似於上下文。

總結

select的缺點:

(1)每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大

(2)同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大

(3)select支持的文件描述符數量太小了,默認是1024(不同平台對FD_SETSIZE設定不一樣)

(4)select接口使用並不靈活,無法分步提交集合,也無法將提交和查詢分步,必須在一次調用中完成

(4)fd_set不能逆向轉換為fd,需要再單獨維護一份描述符的列表

而kqueue剛好能彌補這些缺陷,但卻無法在其它平台使用

關於兩種模型的實現示例下載:

SocketServer_select.zip

SocketServer_kqueue.zip


  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved