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