一、套接字模式
1、阻塞模式
創建套接字時,默認是阻塞模式,對recv函數調用會使程序進入等待狀態,知道接收到數據才返回。
2、非阻塞模式:
可以調用ioctlsocket函數顯式地讓套接字工作在非阻塞模式下。
u_long ul = 1; SOCKET s = ::socket(AF_INET,SOCK_STREAM,0); ::ioctlsocket(s,FIONBIO,(u_long*)&ul);
3、windows提供的I/O模型
1、Select模型
使用select函數來管理I/O
#include "../../common/InitSock.h" #include <stdio.h> CInitSock initsock; int main(){ USHORT nPort = 4567; SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(nPort); sin.sin_addr.S_un.S_addr = INADDR_ANY; //服務端一般這樣這是地址 //綁定套接字到本地機器 if(::bind(sListen,(sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR){ printf("Failed bind()\n"); return -1; } //進入監聽模式 ::listen(sListen,5); //select模型處理過程 //1)初始化一個套接字fdsocket,添加監聽套接字句柄到這個集合 fd_set fdsocket; //所有可用套接字集合 FD_ZERO(&fdsocket); FD_SET(sListen,&fdsocket); while(TRUE){ //2)將fdsocket集合的一個拷貝fdRead傳遞給select函數 // 當有事情發生時,select函數移除fdRead集合中沒有未決I/O操作的套接字句柄,然後返回 fd_set fdRead = fdsocket; int nRet = ::select(0,&fdRead,NULL,NULL,NULL); if(nRet > 0){ //3)通過將原來fdsocket集合與select處理過的fdread集合比較 // 確定有哪些套接字有未決I/O, 並進一步處理這些I/O for (int i = 0; i != (int)fdsocket.fd_count; ++i) { if(FD_ISSET(fdsocket.fd_array[i],&fdRead)){ if(fdsocket.fd_array[i] == sListen){//(1)監聽套接字接收到新連接 if(fdsocket.fd_count < FD_SETSIZE){ sockaddr_in addrRemote; int nAddrLen = sizeof(addrRemote); SOCKET sNew = ::accept(sListen,(SOCKADDR*)&addrRemote,&nAddrLen); FD_SET(sNew,&fdsocket); printf("接收到連接%s\n",::inet_ntoa(addrRemote.sin_addr)); }else{ printf("too much connections!\n"); continue; } }else{ char szText[256]; int nRecv = ::recv(fdsocket.fd_array[i],szText,strlen(szText),0);//可讀 if(nRecv > 0){ szText[nRecv] = '\n'; printf("接收到數據:%s",szText); }else{ //連接關閉 重啟或中斷 ::closesocket(fdsocket.fd_array[i]); FD_CLR(fdsocket.fd_array[i],&fdsocket); } } } } }else{ printf("Failed select()\n"); break; } } return 0; }
2、WSAAsyncSelect模型
WSAAsyncSelect模型允許應用程序以windows消息的形式接受到網絡時間通知。 MFC的CSocket也是該模型。
(為適應windows的消息驅動環境而設置的,現在許多對性能要求不高的網絡應用程序都采用WSAASyncSelect模型)
3、WSAEventSelect模型
4、重疊(Overlapped)I/O模型