1. 程式人生 > >一.Windows I/O模型之選擇(select)模型

一.Windows I/O模型之選擇(select)模型

寫入 lap 調用 pla lose 結構 fd_set 關閉 監視

1.選擇(select)模型:
選擇模型:通過一個fd_set集合管理套接字,在滿足套接字需求後,通知套接字。讓套接字進行工作。避免套接字進入阻塞模式,進行無謂的等待。選擇模型的核心的FD_SET集合和select函數。通過該函數,我們可以們判斷套接字上是否存在數據,或者能否向一個套接字寫入數據。

2.select函數:
int select(
int nfds,//忽略,只是為了兼容而存在。
fd_set FAR* readfds,//可讀性檢查(有數據可讀入,連接關閉,重設,終止)
fd_set FAR* writefds,//可寫性檢查(有數據可發出)
fd+set FAR* exceptfds,//帶外數據檢查(帶外數據)
const struct timeval FAR* timeout//超時
);

3.select模型的工作步驟:
(1)首先把套接字加入到fd_set集合
(2)檢查套接字的可讀寫性
(3)檢查套接字是否還在fd_set集合上
(4)處理數據

4.在三個參數中(readfds、writefds和exceptfds),任何兩個都可以是空值;但是,至少有一個不能為空值!最後一個參數timeout對應的是一個指針,它指向一個timeval結構,用於決select最多等待I/O操作完成多久的時間。如timeout是一個空指針,那麽select函數會無限期地“等待下去,直到至少有一個套接字符合指定的條件後返回。select成功完成後,會在fd_set集合中,返回未完成的I/O操作的套接字句柄的總量。若超時,便會返回0。不管由於什麽原因,假如select調用失敗,都會返回SOCKET_ERROR錯誤。

5.timeval結構體定義:
struct timeval
{
long tv_sec;//秒數
long tv_usec;//毫秒數
};

6.fd_set集合:用select函數對套接字進行監視之前,必須要將套接字分配給一個fd_set集合,設置好讀、寫以及帶外數據的fd_set結構。將一個套接字分配給任何一個集合後,再來調用select進行監視,便可知道一個套接字上是否正在發生上述的I/O活動。Winsock提供了下列宏操
作,對fd_set進行處理和檢查:
FD_ZERO(*set):初始化set
FD_SET(s, *set):將套接字s加入集合set
FD_CLR(s, *set):從set中刪除套接字s。
FD_ISSET(s,*set):檢查s是否還在集合set上,在調用select函數之前必須對此進行判斷。

7.select模型的工作步驟:
(1) 使用FD_ZERO宏,初始化自己感興趣的每一個fd_set。
(2) 使用FD_SET宏,將套接字句柄分配給自己感興趣的每個fd_set。
(3) 調用select函數,等待I/O操作的完成。
(4) 根據select的返回值,我們便可判斷出哪些套接字存在著尚未完成(待決)的I/O操作,.具體的方法是使用FD_ISSET宏,對每個fd_set集合進行檢查。
(5) 知道了每個集合中“待決”的I/O操作之後,對I/O進行處理,然後返回步驟1 ),繼續進行select處理。
(6)select返回後,它會修改每個fd_set結構,刪除那些不存在待決I/O操作的套接字句柄。這正是我們在上述的步驟( 4 )中,為何要使用FD_ISSET宏來判斷一個特定的套接字是否仍在集合中的原因。

示例代碼:

技術分享
 1 SOCKET s;
 2 fd_set fdread;
 3 int ret;
 4 
 5 //初始化
 6 ...
 7 
 8 //Manage I/O on the socket
 9 while(1)
10 {
11     FD_ZERO(&fdread);//初始化集合
12 
13     FD_SET(s,&fdread);//添加套接字到集合上
14 
15     ret=select(0,&fdread,NULL,NULL,NULL);//調用select函數監視網絡事件的完成情況
16     if(ret==SOCKET_ERROR)
17     {
18 ... 19 } 20 21 if(res>0) 22 { 23 //處理數據 24 ... 25 26 if(FD_ISSET(s,&fdread))//檢查套接字是否還在集合上 27 { 28 ... 29 } 30 } 31 32 }
View Code

一.Windows I/O模型之選擇(select)模型