一、套接字模式
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模型