用戶在ADAM-4501上使用TCP/IP方式通訊時,,當(dāng)服務(wù)器發(fā)送命令時,進(jìn)行后續(xù)動作,,但服務(wù)器不發(fā)命令時,,會等待,導(dǎo)致其它操作無法正常執(zhí)行,。recv這類函數(shù)是阻塞函數(shù),,也就是說沒有得到數(shù)據(jù)是不會返回的,這就造成了一個問題,,程序執(zhí)行到這些函數(shù)里面的時候就一直等待,,而這個時候如果要有其他的操作根本得不到響應(yīng)。而select函數(shù)就是為了解決這這個問題,。它將很多個阻塞函數(shù)做成一個集合,,只要這些函數(shù)中任何一個有數(shù)據(jù)輸入了,,它馬上返回,然后判斷是哪一個有輸入,,再進(jìn)行相應(yīng)的操作,。
select模型的中心思想就是利用select函數(shù),實(shí)現(xiàn)對I/O的管理,。利用select函數(shù),,我們可以判斷套接字上是否存在數(shù)據(jù),或者能否向一個套接字寫入數(shù)據(jù),。利用這個函數(shù)可以防止應(yīng)用程序在一次I/O的綁定調(diào)用中進(jìn)入鎖定狀態(tài),。
select函數(shù)原型:
int select(
__in int nfds, //忽略
__inout fd_set *readfds, //檢查可讀性
__inout fd_set *writefds, //檢查可寫性
__inout fd_set *exceptfds, //用于例外數(shù)據(jù)
__in const struct timeval *timeout //超時時間,傳遞NULL會無限期等待下去,,0會立刻返回
);
可讀性說明:
1.有數(shù)據(jù)可以讀入,。
2.連接已經(jīng)關(guān)閉,重設(shè)或者中止,。
3.加入調(diào)用了listen,,而且一個連接正在建立,那么accept函數(shù)調(diào)用會成功,。
關(guān)于連接已經(jīng)關(guān)閉,,重設(shè)或者中止的判斷:
當(dāng)一個套接字在調(diào)用了select之后具有可讀性,那么這個時候我們可以通過調(diào)用recv獲得數(shù)據(jù),。如果真的有數(shù)據(jù)發(fā)送過來,,那么這個調(diào)用會成功。如果是關(guān)閉,,重設(shè)或者中止,,那么recv的調(diào)用會失敗,這個時候通過wsagetlasterror就可以判斷連接是否已經(jīng)中斷,。
可寫性說明:
1.有數(shù)據(jù)可以發(fā)出,。
2.如果已完成了對一個非鎖定連接調(diào)用處理,連接就會成功,。
對于可寫性的檢查,,最好放在需要寫數(shù)據(jù)的時候進(jìn)行檢查。如果和可讀性放在同一個地方進(jìn)行檢查,,那么select很可能每次都會因?yàn)榭蓪懶詸z查成功而返回,。
例外數(shù)據(jù)說明:
1.加入已完成了對一個非鎖定連接調(diào)用的處理,連接嘗試就會失敗,。
2.有帶外數(shù)據(jù)可供讀寫,。
fd_set幾個宏的說明:
FD_SETSIZE 定義了fd_set所允許存放套接字的最大個數(shù),默認(rèn)是64,。
FD_CLR(s,*set):從set中刪除套接字s,。
FD_ISSET(s, *set):檢查s是否set集合的一名成員,;如答案是肯定的是,則返回TRUE,。
FD_SET(s, *set):將套接字s加入集合set,。
FDZERO(*set):將set初始化成空集合。
select調(diào)用流程:
1) 使用FDZERO宏,,初始化自己感興趣的每一個fd_set,。
2) 使用FDSET宏,將套接字句柄分配給自己感興趣的每個fd_set,。
3) 調(diào)用select函數(shù),,然后等待在指定的fd_set集合中,I/O活動設(shè)置好一個或多個套接字句柄,。select完成后,,會返回在所有fd_set集合中設(shè)置的套接字句柄總數(shù),它會修改每個fd_set結(jié)構(gòu),,刪除那些不存在待決I/O操作的套接字句柄
4) 根據(jù)select的返回值,,我們的應(yīng)用程序便可判斷出哪些套接字存在著尚未完成(待決)的I/O操作—具體的方法是使用FD_ISSET宏,對每個fd_set集合進(jìn)行檢查,。
5) 知道了每個集合中“待決”的I/O操作之后,,對I/O進(jìn)行處理,然后返回步驟1 ),,繼續(xù)進(jìn)行select處理,。
如下例
int sockfd;
fd_set fdR;
struct timeval timeout = ..;
...
for(;;) {
FD_ZERO(&fdR);
FD_SET(sockfd, &fdR);
switch (select(sockfd + 1, &fdR, NULL, &timeout)) {
case -1:
error handled by u;
case 0:
timeout hanled by u;
default:
if (FD_ISSET(sockfd)) {
now u read orrecv something;
}
}
}
|