Socket编程实践(8) --Select-I/O复用
五種I/O模型介紹
(1)阻塞I/O[默認]
? ?當上層應用App調用recv系統調用時,如果對等方沒有發送數據(Linux內核緩沖區中沒有數據),上層應用Application1將阻塞;當對等方發送了數據,Linux內核recv端緩沖區數據到達,內核會把數據copy給用戶空間。然后上層應用App解除阻塞,執行下一步操作。
?
(2)非阻塞I/O[少用]
? ?上層應用App將套接字設置成非阻塞模式,?然后循環調用recv函數,接受數據。若緩沖區沒有數據,上層應用不會阻塞,recv返回值為-1,錯誤碼是EWOULDBLOCK。
? ?上層應用程序不斷輪詢有沒有數據到來。造成上層應用忙等待。大量消耗CPU。因此非阻塞模式很少直接用。應用范圍小,一般和IO復用配合使用。
?
(3)I/O多路復用[重點]
? ?上層應用App調用select等其他IO復用系統調用(該機制由Linux內核支持,避免了App忙等待),進行輪詢文件描述符的狀態變化;?當select管理的文件描述符沒有數據(或者狀態沒有變化時),上層應用也會阻塞。
? ?好處是:select機制可以管理多個文件描述符;?可以將select看成一個管理者,用select來管理多個IO,?一旦檢測到的一個IO或者多個IO,有我們感興事件發生時,select函數將返回,返回值為檢測到的事件個數。進而可以利用select相關API函數,操作具體事件。
? ?select函數可以設置等待時間,避免了上層應用App長期僵死。
? ?和阻塞IO模型相比,select?I/O復用模型相當于提前阻塞了。等到有數據到來時,再調用recv就不會發生阻塞。
?
(4)信號驅動I/O[并不常用]
? ?這種用于模型用的比較少,屬于典型的“拉模式(上層應用被動的去Linux內核空間中拉數據)”。即:上層應用App,需要調用recv函數把數據拉進來,會有時間延遲,我們無法避免在延遲時,又有新的信號的產生。
?
(5)異步I/O[并不常用]
? ?異步IO屬于典型的“推模式”,?是效率最高的一種模式,上層應用程序App有異步處理的能力(在Linux內核的支持下,處理其他任務的同時,也可支持IO通訊,?與Windows平臺下的完成端口作用類似IOCP)。
?
Select-I/O復用
#include <sys/select.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);? ? select實現的是一個管理者的功能:?用select來管理多個IO,?一旦其中的一個IO或者多個IO檢測到我們所感興趣的事件,?select就返回,?返回值就是檢測到的事件個數,?并且由第2~4個參數返回那些IO發送了事件,?這樣我們就可以遍歷這些事件,?進而處理這些事件;
參數:
nfds: is?the?highest-numbered?file?descriptor?in?any?of?the?three?sets,plus?1[讀,寫,異常集合中的最大文件描述符+1].
fd_set[四個宏用來對fd_set進行操作]
???????FD_CLR(int?fd,?fd_set?*set);
???????FD_ISSET(int?fd,?fd_set?*set);
???????FD_SET(int?fd,?fd_set?*set);
???????FD_ZERO(fd_set?*set);
timeout[從調用開始到select返回前,會經歷的最大等待時間,?注意此處是指的是相對時間]
//timeval結構: struct timeval {long tv_sec; /* seconds */long tv_usec; /* microseconds */ }; //一些調用使用3個空的set, n為0, 一個非空的timeout來達到較為精確的sleep.Linux中,?select函數改變了timeout值,用來指示還剩下的時間,但很多實現并不改timeout。
為了較好的可移植性,timeout在循環中一般常被重新賦初值。
?
Timeout取值:
? ??timeout==?NULL
? ??? ??無限等待,被信號打斷時返回-1,?errno?設置成?EINTR
? ??timeout->tv_sec?==?0?&&?tvptr->tv_usec?==?0
? ??? ??不等待立即返回
? ??timeout->tv_sec?!=?0?||?tvptr->tv_usec?!=?0
? ??? ??等待特定時間長度,?超時返回0
?
返回值:
??On?success,?select()?and?pselect()?return?the?number?of??file??descriptors??contained??in??
the??three??returned?descriptor?sets?(that?is,?the?total?number?of?bits?that?are??set??in??
readfds,??writefds,??exceptfds)?which??may??be??zero?if?the?timeout?expires?before?anything?
interesting?happens.??On?error,?-1?is?returned,?and?errno?is?set?appropriately;?the?sets??
and??timeout??become??undefined,?so?do?not?rely?on?their?contents?after?an?error.
? ?如果成功,返回所有sets中描述符的個數;如果超時,返回0;如果出錯,返回-1.
?
讀,?寫,?異常事件發生條件 | ||
可讀: | 可寫: | 異常: |
套接口緩沖區有數據可讀(連接的對等方發送數據過來,?填充了本地套接口緩沖區,?所以導致套接口緩沖區有數據可讀); | 套接口發送緩沖區有空間容納數據(因為大部分時間發送緩沖區是未滿的,?因此我們一般不關心這個事件); | 套接口存在帶外數據; ? |
連接的讀一半(對端)關閉(對方調用了close),?即接收到FIN段,?讀操作將返回0; | 連接的寫一半關閉.?即收到RST段之后,?再次調用write操作; | ? |
如果是監聽套接口,?已完成隊列不為空時; | 套接口發生了一個錯誤待處理,?錯誤可以通過getsockopt指定SO_ERROR選項來獲取; | ? |
套接口發生了一個錯誤等待處理,?錯誤可以通過getsockopt指定SO_ERROR選項來獲取; | ? | |
完整源代碼請參照:
http://download.csdn.net/detail/hanqing280441589/8486517
總結
以上是生活随笔為你收集整理的Socket编程实践(8) --Select-I/O复用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JDK 5.0 的新语法
- 下一篇: 未能加载文件或程序集“xxx”或它的某一