WSAEventSelect模型事件触发条件说明
1. FD_READ事件
调用WSAEventSelect函数时,如果当前有数据可读
有数据到达时,并且没有发送过FD_READ事件
调用recv/recvfrom函数后,仍然有数据可读时
2. RD_WRITE事件
调用WSAEventSelect函数时,如果调用能够发送数据时
调用connect()/accept()后,连接已经建立时
调用send()/sendto()函数后,返回WSAEWOULDBLOCK错误后,再次调用send()/sendto()函数可能成功时
3. FD_ACCEPT事件
调用WSAEventSelect函数时,有连接请求需要建立
连接请求到达,未有发送FD_ACCEPT事件
调用accept()函数后,还有连接请求需要建立
4. FD_CONNECT事件
调用WSAEventSelect函数时,一个连接已经建立完成
调用connect()函数后,建立连接完成时
5. FD_CLOSE事件
调用WSAEventSelect函数时,socket连接关闭
从容关闭,没有数据可读
执行shutdown()从容关闭,对方应答FIN后,无数据需要读取
对方关闭连接,WSAECONNRESET错误发生
WSAEventSelect()函数和WSAAsyncSelect()函数类似,它们的区别在于当一个FD_XXX网络事件发生时,WSAEventSelect()函数将导致一个应用程序指定的事件对象将被设置,即将网络事件投递到一个事件对象句柄,而不是将网络事件(消息)投递至一个窗口句柄。
WSAEventSelect()函数原型如下:
int WSAEventSelect(
SOCKET s, //一个标识套接口的描述字
WSAEVENT hEventObject, //是一个由WSACreateEvent(?)函数创建的事件对象句柄,用于标识与所提供的FD_XXX网络事件集合相关的一个事件对象
long lNetworkEvents //指定应用程序感兴趣的各种网络事件(FD_XXX)的组合
);
SOCKET s, //一个标识套接口的描述字
WSAEVENT hEventObject, //是一个由WSACreateEvent(?)函数创建的事件对象句柄,用于标识与所提供的FD_XXX网络事件集合相关的一个事件对象
long lNetworkEvents //指定应用程序感兴趣的各种网络事件(FD_XXX)的组合
);
以下为测试WSAEventSelect()函数的程序,一个服务器端两个客户端
下面是服务器端程序:
/************************************************************************/
/* 事件对象I/O管理程序实例 */
/************************************************************************/
#include <WINSOCK2.H>
#pragma comment(lib,"ws2_32")
#include <stdio.h>
int main()
{
printf("服务端程序\n");
//------①加载----------
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
printf("WSAStartup Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("①加载成功\n");
//-------②创建流式套接字------------
SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (s==INVALID_SOCKET)
{
printf("socket() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("②已创建监听套接口:【%d】\n",s);
//将套接口s置于”非阻塞模式“
u_long u1=1;
ioctlsocket(s,FIONBIO,(u_long*)&u1);
//-----------③绑定本地地址---------------------
struct sockaddr_in Sadd;
Sadd.sin_family=AF_INET;
Sadd.sin_port=htons(5555);
Sadd.sin_addr.S_un.S_addr=inet_addr("192.168.31.1");
if (bind(s,(sockaddr*)&Sadd,sizeof(Sadd))==SOCKET_ERROR)
{
printf("bind() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("③绑定成功,本地IP地址:【%s】,端口号:【%d】\n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));
//--------------④进入监听状态-----------------
if (listen(s,5)==SOCKET_ERROR)
{
printf("listen Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("④进入监听状态\n");
//--------------⑤创建事件对象-----------------
WSAEVENT NewEvent=WSACreateEvent();
if (NewEvent==WSA_INVALID_EVENT)
{
printf("WSACreateEvent() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("⑤创建一个事件对象,返回的事件对象句柄NewEvent=%d\n",NewEvent);
//--------------⑥网络事件注册------------
int WESerror=WSAEventSelect(s,NewEvent,FD_ACCEPT|FD_CLOSE);
if (WESerror==INVALID_SOCKET)
{
printf("WSAEventSelect() Failed,Error=【%d】\n",WSAGetLastError());
return -1;
}
else
printf("⑥套接口【%d】、事件对象【%d】和网络事件FD_ACCEPT|FD_CLOSE已关联\n",s,NewEvent);
//-----------准备工作---------------
int t=1;
WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];
int n=0;
eventArray[n]=NewEvent;
sockArray[n]=s;
n++;
//------------循环处理-------------
while (true)
{
//---------------⑦等待事件对象--------------
int nIndex=WSAWaitForMultipleEvents(n,eventArray,FALSE,40000,FALSE);
printf("nIndex=%d\n",nIndex);
if (nIndex==WSA_WAIT_FAILED)//------7.1调用失败---------
{
printf("调用失败\n");
break;
}
else if (nIndex==WSA_WAIT_TIMEOUT)//-------7.2超时---------
{
if (t<3)
{
printf("第【%d】次超时\n",t);
t++;
continue;
}
else
{
printf("第【%d】次超时,退出\n",t);
break;
}
}
//---------------7.3网络事件触发事件对象句柄的工作状态--------
else
{
WSANETWORKEVENTS event;//该结构记录网络事件和对应出错代码
//---------⑧网络事件查询-----------
WSAEnumNetworkEvents(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,&event);
WSAResetEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
if ((event.lNetworkEvents&FD_ACCEPT)!=0) //------8.1处理FD_ACCEPT通知消息
{
if (event.iErrorCode[FD_ACCEPT_BIT]==0)
{
if (n>WSA_MAXIMUM_WAIT_EVENTS)
{
printf("Too many connections!\n");
break;
}
SOCKET sNew=accept(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,NULL);
NewEvent=WSACreateEvent();
WSAEventSelect(sNew,NewEvent,FD_READ|FD_CLOSE);
eventArray[n]=NewEvent; /* 将新的连接加入数组 */
sockArray[n]=sNew;
n++;
}
}
else if (event.lNetworkEvents&FD_READ) //-------8.2处理FD_READ通知消息
{
if (event.iErrorCode[FD_READ_BIT]==0)
{
char buf[256];
memset(buf,0,256);
int nRecv=recv(sockArray[nIndex-WSA_WAIT_EVENT_0],buf,sizeof(buf),0);
if (nRecv>0)
{
printf("接收到客户端【%d】数据:%s\n",sockArray[nIndex-WSA_WAIT_EVENT_0],buf);
}
}
}
else if (event.lNetworkEvents&FD_CLOSE) //---------8.3处理FD_CLOSE通知消息
{
if (event.iErrorCode[FD_CLOSE_BIT]==0)
{
closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]);
WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
printf("套接字为【%d】的已关闭连接\n",sockArray[nIndex-WSA_WAIT_EVENT_0]);
}
else
{
if (event.iErrorCode[FD_CLOSE_BIT]==10053)
{
closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]);
WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
printf("客户端【%d】非法关闭连接\n",sockArray[nIndex-WSA_WAIT_EVENT_0]);
}
}
for (int j=nIndex-WSA_WAIT_EVENT_0;j<n-1;j++)
{
sockArray[j]=sockArray[j+1];
eventArray[j]=eventArray[j+1];
}
n--;
}
}// end 网络事件触发
}//end while
printf("退出服务器程序\n");
closesocket(s);
WSACleanup();
return 0;
}
view plaincopy to clipboardprint?
//Client 1
#include <winsock2.h>
#pragma comment(lib,"WS2_32")
#include <stdio.h>
int main()
{
printf("客户端程序/n");
//----------------①???加??载?---------------------------------------------------------
WSADATA wsaData;
WORD wVersionRequested=MAKEWORD(2,2);
if(WSAStartup(wVersionRequested,&wsaData)!=0){
printf("WSAStartup() Failed,Error=/n",WSAGetLastError());
return 1;
}
else
printf("①加载成功|/n");
//----------------②???创???建??流???式??套???节??字??------------------------------------------------
SOCKET c1;
c1 = socket(AF_INET, SOCK_STREAM,0);
if(c1 == INVALID_SOCKET){
printf("socket() Failed,Error=/n",WSAGetLastError());
return 1;
}
else
printf("②已创建连接套接字:【?%d 】/n",c1);
//----------------绑???定??本??地??地??址??------------------------------------------------
struct sockaddr_in C1add;
C1add.sin_family=AF_INET;
C1add.sin_port=htons(2222);
C1add.sin_addr.s_addr=inet_addr("192.168.31.2");
if(bind(c1,(sockaddr*)&C1add,sizeof(C1add))==SOCKET_ERROR){
printf("bind() Failed,Error=/n",WSAGetLastError());
return 1;
}
else
printf("绑定成功,本地IP地址:【%s 】,端口号:【 %d 】/n",inet_ntoa(C1add.sin_addr),ntohs(C1add.sin_port));
//------------------③??连??接??请?求??------------------------------------------------
struct sockaddr_in Sadd;
Sadd.sin_family=AF_INET;
Sadd.sin_port=htons(5555);
Sadd.sin_addr.s_addr=inet_addr("192.168.31.1");
if(connect(c1, (sockaddr*)&Sadd, sizeof(Sadd)) == -1){
printf(" Failed connect(),Error=【 %d 】/n",WSAGetLastError());
return 1;
}
else //*************************连??接??成??功|,可??以?? 开a始??发???送??、??接??收??*************************
{
printf("③连接成功|,服t务器IP地址:【 %s 】,端口号:【 %d 】/n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));
int a;
printf("希望发送数y据Y吗e?(键入“??1”??发???送??)");
scanf("%d",&a);
while(a==1) //------循-环??处?|理???------
{ //-----发???送??------
char S_buf[] = "Hello!I am a client 1";
int isend=send(c1,S_buf,strlen(S_buf),0);
if(isend==SOCKET_ERROR){
printf("Failed send(),Error=【? %d 】?,或??者?服?t务?器??意?a外?a关?闭??/n",WSAGetLastError());
return 1;
}
else if(isend!=0)
printf("信?息??【? %s 】?已??发???送??/n",S_buf);
else
printf("信?息??无T法???发???送??给?服?t务?端?/n");
printf("希??望??继??续?发???送??数?y据Y吗e???(键??入??“??1”??继??续?发???送??)");
scanf("%d",&a);
if(a!=1)
break;
} //------end 循-环??处?|理???------
} //*************************end 开a始??发???送??、??接??收??*************************
//------------------④???关?闭??、??释???放??------------------------------------------------
closesocket(c1);
WSACleanup();
printf("④???与??服?t务?器??连??接??完???毕??/n");
return 0;
}
/************************************************************************/
/* 事件对象I/O管理程序实例 */
/************************************************************************/
#include <WINSOCK2.H>
#pragma comment(lib,"ws2_32")
#include <stdio.h>
int main()
{
printf("服务端程序\n");
//------①加载----------
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
printf("WSAStartup Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("①加载成功\n");
//-------②创建流式套接字------------
SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (s==INVALID_SOCKET)
{
printf("socket() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("②已创建监听套接口:【%d】\n",s);
//将套接口s置于”非阻塞模式“
u_long u1=1;
ioctlsocket(s,FIONBIO,(u_long*)&u1);
//-----------③绑定本地地址---------------------
struct sockaddr_in Sadd;
Sadd.sin_family=AF_INET;
Sadd.sin_port=htons(5555);
Sadd.sin_addr.S_un.S_addr=inet_addr("192.168.31.1");
if (bind(s,(sockaddr*)&Sadd,sizeof(Sadd))==SOCKET_ERROR)
{
printf("bind() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("③绑定成功,本地IP地址:【%s】,端口号:【%d】\n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));
//--------------④进入监听状态-----------------
if (listen(s,5)==SOCKET_ERROR)
{
printf("listen Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("④进入监听状态\n");
//--------------⑤创建事件对象-----------------
WSAEVENT NewEvent=WSACreateEvent();
if (NewEvent==WSA_INVALID_EVENT)
{
printf("WSACreateEvent() Failed,Error=【%d】\n",WSAGetLastError());
return 1;
}
else
printf("⑤创建一个事件对象,返回的事件对象句柄NewEvent=%d\n",NewEvent);
//--------------⑥网络事件注册------------
int WESerror=WSAEventSelect(s,NewEvent,FD_ACCEPT|FD_CLOSE);
if (WESerror==INVALID_SOCKET)
{
printf("WSAEventSelect() Failed,Error=【%d】\n",WSAGetLastError());
return -1;
}
else
printf("⑥套接口【%d】、事件对象【%d】和网络事件FD_ACCEPT|FD_CLOSE已关联\n",s,NewEvent);
//-----------准备工作---------------
int t=1;
WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];
int n=0;
eventArray[n]=NewEvent;
sockArray[n]=s;
n++;
//------------循环处理-------------
while (true)
{
//---------------⑦等待事件对象--------------
int nIndex=WSAWaitForMultipleEvents(n,eventArray,FALSE,40000,FALSE);
printf("nIndex=%d\n",nIndex);
if (nIndex==WSA_WAIT_FAILED)//------7.1调用失败---------
{
printf("调用失败\n");
break;
}
else if (nIndex==WSA_WAIT_TIMEOUT)//-------7.2超时---------
{
if (t<3)
{
printf("第【%d】次超时\n",t);
t++;
continue;
}
else
{
printf("第【%d】次超时,退出\n",t);
break;
}
}
//---------------7.3网络事件触发事件对象句柄的工作状态--------
else
{
WSANETWORKEVENTS event;//该结构记录网络事件和对应出错代码
//---------⑧网络事件查询-----------
WSAEnumNetworkEvents(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,&event);
WSAResetEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
if ((event.lNetworkEvents&FD_ACCEPT)!=0) //------8.1处理FD_ACCEPT通知消息
{
if (event.iErrorCode[FD_ACCEPT_BIT]==0)
{
if (n>WSA_MAXIMUM_WAIT_EVENTS)
{
printf("Too many connections!\n");
break;
}
SOCKET sNew=accept(sockArray[nIndex-WSA_WAIT_EVENT_0],NULL,NULL);
NewEvent=WSACreateEvent();
WSAEventSelect(sNew,NewEvent,FD_READ|FD_CLOSE);
eventArray[n]=NewEvent; /* 将新的连接加入数组 */
sockArray[n]=sNew;
n++;
}
}
else if (event.lNetworkEvents&FD_READ) //-------8.2处理FD_READ通知消息
{
if (event.iErrorCode[FD_READ_BIT]==0)
{
char buf[256];
memset(buf,0,256);
int nRecv=recv(sockArray[nIndex-WSA_WAIT_EVENT_0],buf,sizeof(buf),0);
if (nRecv>0)
{
printf("接收到客户端【%d】数据:%s\n",sockArray[nIndex-WSA_WAIT_EVENT_0],buf);
}
}
}
else if (event.lNetworkEvents&FD_CLOSE) //---------8.3处理FD_CLOSE通知消息
{
if (event.iErrorCode[FD_CLOSE_BIT]==0)
{
closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]);
WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
printf("套接字为【%d】的已关闭连接\n",sockArray[nIndex-WSA_WAIT_EVENT_0]);
}
else
{
if (event.iErrorCode[FD_CLOSE_BIT]==10053)
{
closesocket(sockArray[nIndex-WSA_WAIT_EVENT_0]);
WSACloseEvent(eventArray[nIndex-WSA_WAIT_EVENT_0]);
printf("客户端【%d】非法关闭连接\n",sockArray[nIndex-WSA_WAIT_EVENT_0]);
}
}
for (int j=nIndex-WSA_WAIT_EVENT_0;j<n-1;j++)
{
sockArray[j]=sockArray[j+1];
eventArray[j]=eventArray[j+1];
}
n--;
}
}// end 网络事件触发
}//end while
printf("退出服务器程序\n");
closesocket(s);
WSACleanup();
return 0;
}
view plaincopy to clipboardprint?
//Client 1
#include <winsock2.h>
#pragma comment(lib,"WS2_32")
#include <stdio.h>
int main()
{
printf("客户端程序/n");
//----------------①???加??载?---------------------------------------------------------
WSADATA wsaData;
WORD wVersionRequested=MAKEWORD(2,2);
if(WSAStartup(wVersionRequested,&wsaData)!=0){
printf("WSAStartup() Failed,Error=/n",WSAGetLastError());
return 1;
}
else
printf("①加载成功|/n");
//----------------②???创???建??流???式??套???节??字??------------------------------------------------
SOCKET c1;
c1 = socket(AF_INET, SOCK_STREAM,0);
if(c1 == INVALID_SOCKET){
printf("socket() Failed,Error=/n",WSAGetLastError());
return 1;
}
else
printf("②已创建连接套接字:【?%d 】/n",c1);
//----------------绑???定??本??地??地??址??------------------------------------------------
struct sockaddr_in C1add;
C1add.sin_family=AF_INET;
C1add.sin_port=htons(2222);
C1add.sin_addr.s_addr=inet_addr("192.168.31.2");
if(bind(c1,(sockaddr*)&C1add,sizeof(C1add))==SOCKET_ERROR){
printf("bind() Failed,Error=/n",WSAGetLastError());
return 1;
}
else
printf("绑定成功,本地IP地址:【%s 】,端口号:【 %d 】/n",inet_ntoa(C1add.sin_addr),ntohs(C1add.sin_port));
//------------------③??连??接??请?求??------------------------------------------------
struct sockaddr_in Sadd;
Sadd.sin_family=AF_INET;
Sadd.sin_port=htons(5555);
Sadd.sin_addr.s_addr=inet_addr("192.168.31.1");
if(connect(c1, (sockaddr*)&Sadd, sizeof(Sadd)) == -1){
printf(" Failed connect(),Error=【 %d 】/n",WSAGetLastError());
return 1;
}
else //*************************连??接??成??功|,可??以?? 开a始??发???送??、??接??收??*************************
{
printf("③连接成功|,服t务器IP地址:【 %s 】,端口号:【 %d 】/n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));
int a;
printf("希望发送数y据Y吗e?(键入“??1”??发???送??)");
scanf("%d",&a);
while(a==1) //------循-环??处?|理???------
{ //-----发???送??------
char S_buf[] = "Hello!I am a client 1";
int isend=send(c1,S_buf,strlen(S_buf),0);
if(isend==SOCKET_ERROR){
printf("Failed send(),Error=【? %d 】?,或??者?服?t务?器??意?a外?a关?闭??/n",WSAGetLastError());
return 1;
}
else if(isend!=0)
printf("信?息??【? %s 】?已??发???送??/n",S_buf);
else
printf("信?息??无T法???发???送??给?服?t务?端?/n");
printf("希??望??继??续?发???送??数?y据Y吗e???(键??入??“??1”??继??续?发???送??)");
scanf("%d",&a);
if(a!=1)
break;
} //------end 循-环??处?|理???------
} //*************************end 开a始??发???送??、??接??收??*************************
//------------------④???关?闭??、??释???放??------------------------------------------------
closesocket(c1);
WSACleanup();
printf("④???与??服?t务?器??连??接??完???毕??/n");
return 0;
}