通過呼叫select函式可以確定乙個或多個套接字的狀態,判斷套接字上是否有資料,或
者能否向乙個套接字寫入資料。
select模型是最常見的i/o模型。
使用int select( int nfds , fd_set far* readfds , fd_set far* writefds,fd_set far* exceptfds,const struct timeval far * timeout ) ;
函式來檢查你要呼叫的socket套接字是否已經有了需要處理的資料。
select包含三個socket佇列,分別代表:
readfds ,檢查可讀性,
writefds,檢查可寫性,
exceptfds,例外資料。
timeout是select函式的返回時間。
例如,我們想要檢查乙個套接字是否有資料需要接收,我們可以把套接字控制代碼加入可讀性檢查佇列中,然後呼叫select,如果,該套接字沒有資料需要接收, select函式會把該套接字從可讀性檢查佇列中刪除掉,所以我們只要檢查該套接字控制代碼是否還存在於可讀性佇列中,就可以知道到底有沒有資料需要接收了。
winsock提供了一些巨集用來操作套接字佇列fd_set。
fd_clr( s,*set) 從佇列set刪除控制代碼s。
fd_isset( s, *set) 檢查控制代碼s是否存在與佇列set中。
fd_set( s,*set )把控制代碼s新增到佇列set中。
fd_zero( *set ) 把set佇列初始化成空佇列。
涉及到的結構的定義:
a、 fd_set結構:
#define fd_setsize 64
typedef struct fd_set
fd_set;
fd_count為已設定socket的數量
fd_array為socket列表,fd_setsize為最大socket數量,建議不小於64。這是微軟建
議的。(是否是不應該大於64)
timeval結構:
struct timeval ;
這個結構主要是設定select()函式的等待值,如果將該結構設定為(0,0),則select()函式
會立即返回。
select函式各引數的作用:
1. nfds:沒有任何用處,主要用來進行系統相容用,一般設定為0。
2. readfds:等待可讀性檢查的套接字組。
3. writefds;等待可寫性檢查的套接字組。
4. exceptfds:等待錯誤檢查的套接字組。
5. timeout:超時時間。
函式失敗的返回值:呼叫失敗返回socket_error,超時返回0。
readfds、writefds、exceptfds三個變數至少有乙個不為空,同時這個不為空的套接字組
種至少有乙個socket,道理很簡單,否則要select幹什麼呢。
舉例:測試乙個套接字是否可讀:
fd_set fdread;
fd_set(s,&fdread); //加入套接字
if(fd_isset(s,&fread) //是否存在fread中
1:select模型(選擇模型)
先看一下下面的這句**:
int iresult = recv(s, buffer,1024);
這是用來接收資料的,在預設的阻塞模式下的套接字裡,recv會阻塞在那裡,直到套接字連線上有資料可讀,把資料讀到buffer裡後recv函式才會返回,不然就會一直阻塞在那裡。在單執行緒的程式裡出現這種情況會導致主線程(單執行緒程式裡只有乙個預設的主線程)被阻塞,這樣整個程式被鎖死在這裡,如果永遠沒資料傳送過來,那麼程式就會被永遠鎖死。這個問題可以用多執行緒解決,但是在有多個套接字連線的情況下,這不是乙個好的選擇,擴充套件性很差。select模型就是為了解決這個問題而出現的。
再看**:
int iresult = ioctlsocket(s, fiobio, (unsigned long *)&ul);
iresult = recv(s, buffer,1024);
這一次recv的呼叫不管套接字連線上有沒有資料可以接收都會馬上返回。原因就在於我們用ioctlsocket把套接字設定為非阻塞模式了。不過你跟蹤一下就會發現,在沒有資料的情況下,recv確實是馬上返回了,但是也返回了乙個錯誤:wsaewouldblock,意思就是請求的操作沒有成功完成。看到這裡很多人可能會說,那麼就重複呼叫recv並檢查返回值,直到成功為止,但是這樣做效率很成問題,開銷太大。
感謝天才的微軟工程師吧,他們給我們提供了好的解決辦法。
// link with ws2_32.lib
#pragma comment(lib,"ws2_32.lib")
#include #include #include #include // needed for _wtoi
int __cdecl wmain(int argc, wchar_t **argv)
; int iresult = 0;
iresult = wsastartup(makeword(2, 2), &wsadata);
if (iresult != 0)
socket sock = socket(af_inet, sock_stream ,0);
if (sock == invalid_socket) }
sockaddr_in aseraddr;
aseraddr.sin_addr.s_un.s_addr = inet_addr("127.0.0.1");
aseraddr.sin_family = af_inet;
aseraddr.sin_port = htons(1989);
int iretbind = bind(sock,(sockaddr*)&aseraddr,sizeof(sockaddr_in));
int iretls = listen(sock,10);
sockaddr_in aclientaddr;
int ilen= sizeof(sockaddr_in);
socket sockclient = invalid_socket;
fd_set fdread;
timeval fdtime;
fdtime.tv_sec = 2;
fdtime.tv_usec= 0;
while(1)
if(sockclient!=invalid_socket)
; recv(sockclient,buffer,100,0);
printf("客戶端:%s",buffer);
} }return 0;
}
WinSock學習 1 Select模型
新學的,有錯誤請指出 bool initialsocket socket sock,u short port int findposofset socket s,fd set set int tmain int argc,tchar argv fd set fdset fd zero fdset f...
select模型詳解
client客戶端 include include include include include include include include include include include define maxbuf 1024 int main 初始化伺服器端 對方 的位址和埠資訊 bzero...
Select網路模型
mysockt.h pragma once define maxnum 64 include pragma comment lib,ws2 32.lib define um user wm user 1 向視窗發訊息 enum nettype class cmysocket mysocket.cpp...