生活随笔
收集整理的這篇文章主要介紹了
【网络编程】之六、选择select
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
? select模型在五中模型中是最簡單,最容易實(shí)現(xiàn)的,當(dāng)然他的效率當(dāng)然不如其他四種;
select可以去監(jiān)視一個(gè)套接字,看哪個(gè)socket有消息到來;
[cpp]?view plaincopy
int?select(?? ??_In_?????int?nfds,?? ??_Inout_??fd_set?*readfds,?? ??_Inout_??fd_set?*writefds,?? ??_Inout_??fd_set?*exceptfds,?? ??_In_?????const?struct?timeval?*timeout?? );??
來看一下fd_set:
[cpp]?view plaincopy
typedef?struct?fd_set?{??? ?u_int?fd_count;?? ?SOCKET?fd_array[FD_SETSIZE];?? }?fd_set;??
其實(shí)fd_set就是一個(gè)socket的集合。
其中#define FD_SETSIZE 64
所以fd_set最多可以放64個(gè)套接字。
fdset 代表著一系列特定套接字的集合。其中, readfds 集合包括符合下述任何一個(gè)條件的套接字:
● 有數(shù)據(jù)可以讀入。
● 連接已經(jīng)關(guān)閉、重設(shè)或中止。
● 假如已調(diào)用了listen,而且一個(gè)連接正在建立,那么accept函數(shù)調(diào)用會(huì)成功。
writefds 集合包括符合下述任何一個(gè)條件的套接字:
● 有數(shù)據(jù)可以發(fā)出。
● 如果已完成了對一個(gè)非鎖定連接調(diào)用的處理,連接就會(huì)成功。
exceptfds 集合包括符合下述任何一個(gè)條件的套接字:
● 假如已完成了對一個(gè)非鎖定連接調(diào)用的處理,連接嘗試就會(huì)失敗。
● 有帶外(Out-of-band,OOB)數(shù)據(jù)可供讀取。
在select函數(shù)中,中間三個(gè)參數(shù)(readfds, writefds, exceptfds)中,你至少有一個(gè)不是NULL,不為空了也必須要至少包含一個(gè)套接字句柄。如果不滿足這些要求,select函數(shù)就沒有任何東西等待了。
最后一個(gè)參數(shù)timeout是一個(gè)指向timeval結(jié)構(gòu)的指針,
[cpp]?view plaincopy
typedef?struct?timeval?{?? ??long?tv_sec;?? ??long?tv_usec;?? }?timeval;??
他指定用于select函數(shù)等待io操作的最長時(shí)間。 ?如果你傳一個(gè)空進(jìn)去,那么select函數(shù)調(diào)用就會(huì)無限的鎖定或者停止下去,直到有一個(gè)描述符符合指定的條件。
如果你把最后一個(gè)參數(shù)設(shè)置為(0,0),那么就是說select會(huì)立即返回,處于性能的考慮,要避免這樣的設(shè)置。
ok,現(xiàn)在我們的select函數(shù)成功返回了,她會(huì)在fd_set結(jié)構(gòu)中返回剛好有未完成的io操作的所有套接字句柄的總量。如果超時(shí)了,那么就會(huì)返回0。 如果失敗了那么就返回SOCKET_ERROR,我們可以調(diào)用WSAGetLastError函數(shù)來獲取錯(cuò)誤碼。
當(dāng)我們調(diào)用select函數(shù)之前,我們必須要分配一個(gè)fd_set結(jié)構(gòu)集合。然后才可以調(diào)用select函數(shù)。
ok,winsock提供給我們一些宏,我們來看一下:
sock s;
fd_set set;
FD_CLR(s, *set); 從set中刪除套接字s。
FD_ISSET(s, *set);檢查s是否在set中,如果在就返回TRUE,否則就是FALSE;
FD_SET(s, *set);將套接字s放入結(jié)合set中。
FDZERO(*set);將set初始化為空集合。
最后看實(shí)例之前,我們先來看一下select的使用步驟:
1、使用FDZERO初始化一個(gè)fd_set對象。
2、調(diào)用FD_SET,把套接字加入到fd_set集合中。
3、調(diào)用select函數(shù),等待返回。
4、完成后返回所有的fd_set集合中設(shè)置的套接字句柄的總數(shù),對每個(gè)集合進(jìn)行了相應(yīng)的更新。
5、根據(jù)select函數(shù)的返回值,聯(lián)合FD_ISSET對fd_set進(jìn)行檢查。
6、知道了集合中待解決的IO操作后,對IO進(jìn)行處理。 ?返回1,繼續(xù)進(jìn)行select的調(diào)用處理。
貼上服務(wù)器端代碼:
[cpp]?view plaincopy
? ? ? ? ? ? ?? #include<WinSock2.h>?? #include<stdio.h>?? #pragma?comment(lib,"WS2_32.lib")?? ?? bool?select_server(SOCKET?sock,?int?nTime?=?100,?bool?bRead?=?true);?? ?? int?main(int?argc,?char*?argv[])?? {?? ????WSADATA?wsaData;?? ????WORD?sockVersion?=?MAKEWORD(2,0);?? ????::WSAStartup(sockVersion,?&wsaData);?? ?????? ????SOCKET?s?=?::socket(AF_INET,?SOCK_STREAM,?IPPROTO_TCP);?? ????if(s?==?INVALID_SOCKET)?? ????{?? ????????printf("error");?? ????????::WSACleanup();?? ????????return?0;?? ????}?? ?? ????sockaddr_in?sin;?? ????sin.sin_family?=?AF_INET;?? ????sin.sin_port?=?htons(8888);?? ????sin.sin_addr.S_un.S_addr?=?INADDR_ANY;?? ?????? ????if(::bind(s,?(LPSOCKADDR)&sin,?sizeof(sin))?==?SOCKET_ERROR)?? ????{?? ????????printf("error");?? ????????::WSACleanup();?? ????????return?0;?? ????}?? ?????? ????if(::listen(s,?2)?==?SOCKET_ERROR)?? ????{?? ????????printf("error");?? ????????::WSACleanup();?? ????????return?0;?? ????}?? ?? ????sockaddr_in?remoteAddr;?? ????int?nAddrLen?=?sizeof(remoteAddr);?? ????SOCKET?client;?? ????char?szText[]?=?"peter\n";?? ????char?szBuf[1024]?=?{0};?? ?? ????while(1)?? ????{?? ????????fd_set?fdset;?? ????????FD_ZERO(&fdset);?? ????????FD_SET(s,?&fdset);?? ????????timeval?tv;?? ????????tv.tv_sec??=?3;?? ????????tv.tv_usec?=?0;?? ????????int?n;?? ????????if?(n?=?select(0,?&fdset,NULL,?NULL,?&tv)?==?SOCKET_ERROR)?? ????????{?? ????????????continue;?? ????????}?? ????????if(FD_ISSET(s,&fdset))?? ????????{?? ????????????? ?? ????????????client?=?::accept(s,?(SOCKADDR*)&remoteAddr,?&nAddrLen);?? ????????????if(client?==?INVALID_SOCKET)?? ????????????{?? ????????????????printf("error");?? ????????????????continue;?? ????????????}?? ?? ????????????printf("接收到一個(gè)連接:%s\r\n",inet_ntoa(remoteAddr.sin_addr));?? ?? ????????????::send(client,?szText,?strlen(szText),?0);??? ?? ????????????int?re?=?::recv(client,?szBuf,?1024,?0);?? ????????????if(re?>?0)?? ????????????{?? ????????????????szBuf[re]?=?'\n';?? ????????????????printf(szBuf);?? ????????????}?? ?????????? ????????????::closesocket(client);?? ????????}?? ????}?? ?? ????::closesocket(s);?? ????::WSACleanup();?? ????return?0;?? }??
客戶端見前面的
【網(wǎng)絡(luò)編程】之四、socket網(wǎng)絡(luò)編程例解
? ;
稍后會(huì)寫一個(gè)簡易的聊天程序,將源碼貼出,稍后!
2012/8/22
jofranks 于南昌
總結(jié)
以上是生活随笔為你收集整理的【网络编程】之六、选择select的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。