WinSock IO模型 实例


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)的组合
);

以下为测试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;
}
  







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值