Winsock I/O模型有两种模式:阻塞和非阻塞。
阻塞模式下,在I/O操作完成之前,会一直等待下去,效率很低。
非阻塞模式下,要一直检测WSAEWOULDBLOCK错误。
为了提高效率和编程的方便,Winsock提供了几种I/O模型:select、WSAAsyncSelect、WSAEventSelect。
select
select是一个阻塞I/O模型,用于等待一个套接字集合,直到某些套接字变得可用或者超时。
函数成功返回后,则可通过判断一套接字是否在readfds集合中来检查该套接字是否可读。
int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,const struct timeval* timeout);
readfds : 等待可读性检查的套接字组
writefds : 等待可写性检查的套接字组
exceptfds : 等待错误检查的套接字组
struct timeval{
long tv_sec; //s
long tv_usec; //ms
}
四个对fd_set进行操作的宏定义:
FD_CLR(s,*set) FD_ISSET(s,*set) FD_SET(s,*set) FD_ZERO(*set)
WSAAsyncSelect
WSAAsyncSelect是一个非阻塞的异步I/O模型。利用这个模型,套接字可以接收以windows消息为基础的网络事件通知。
int WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);
hWnd是接收windows消息的窗口句柄。
WMsg是网络事件发生时指定窗口接收到的消息。
lEvent用于知名应用程序感兴趣的网络事件集合。FD_READ、FD_WRITE、FD_OOB、FD_ACCEPT、FD_CONNECT、FD_CLOSE。
事件只能注册一次,后面的注册将会覆盖前面的注册。监听套接字的注册对已连接套接字同样有效。
注意:WSAAsyncSelect是非阻塞的,所以不能直接调用accept阻塞来接收客户端连接,需要注册FD_ACCEPT事件,在FD_ACCEPT事件处理时调用accept来就收客户端连接。
wMsg:hWnd得到的消息中wParam表示网络事件发生的套接字,lParam低字节声明了发生的网络事件,高字节含有一个错误代码。
typedef   struct   tagMSG   {       
          HWND       hwnd;        //窗口句柄  
          UINT       message;    //消息常量标识符  
          WPARAM   wParam;   //32位消息的特定附加信息    
          LPARAM   lParam;      //32位消息的特定附加信息  
          DWORD     time;        //消息创建时的时间  
          POINT     pt;             //消息创建时的鼠标位置  
}   MSG;   
其中message就是自定义的消息标示符,通常用如下方式定义:
#define WM_MY_MESSAGE (WM_USER+200)
WSAEventSelect
WSAEventSelect和WSAAsyncSelect不同的是,网络时间不是发送到一个窗口,而是发送到一个事件对象。
首先创建一个事件对象,返回一个事件对象句柄:
WSAEVENT WSACreateEvent(void);//默认状态下事件对象处于未传信(可用)和人工重设模式。
注册网络时间:
int WSAEventSelect(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents);
处于人工重设模式的事件对象在完成一次I/O请求之后要手动复位为未传信。
BOOL WSAResetEvent(WSAEVENT hEvent);
可以使用WSAWaitForMultipleEvents等待网络时间工作状态。
WSAWaitForMultipleEvents返回后,就可以根据返回值得到此次已传信的事件,然后根据时间检索对应的套接字。
index = WSAWaitForMultipleEvents();
MyEvent = EventArray[index-WSA_WAIT_EVENT_0];
然后调用WSAEnumNetworkEvents获取发生了什么网络事件
int WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents);
如果传入hEventObject参数,此函数将会重设hEventObject事件对象。
lpNetworkEvents是一个WSANETWORKEVENTS数组:
typedef struct _WSANETWORKEVENTS{
long lNetworkEvents;
int iErrorCodes[FD_MAX_EVENTS];
}WSANETWORKEVENTS;
lNetworkEvents是指定套接字上发生的所有类型的网络事件,iErrorCodes是和lNetworkEvents联系起来的错误代码。
每种网络事件的错误代码索引是事件名字加上'_BIT’,例如对FD_READ事件,其索引则是FD_READ_BIT。
 
                    
                     
                    
                 
                    
                 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号