API SOCKET基础(五) 异步套接字

前面介绍的socket操作中,有一个非常大的缺陷,当一个socket运行accept,recv,recvfrom等网络操作的时候,程序就要等待函数成功返回一个值后才能继续往下执行。譬如说,一个tcp socket用recv函数接收数据,那么程序的执行就停留在recv语句上一直等待数据的到来,这就是所谓的同步套接字。有米办法让程序不会卡在accept,recv,recvfrom这样的网络操作上呢?简单的方法是把这样的操作放到一个新开的线程上,但这不是一个好方法,会令代码变得复杂和线程增多难以管理。为了解决这个问题异步套接字就产生了。异步套接字的使用流程如下:

1.为工程链接导入库文件 ws2_32.lib ,然后添加头文件 #include <Winsock2.h> ,然后在App类的InitInstance()函数里面加载套接字库,注意必须加载2.0或以上版本的套接字库。

2.下面以对话框工程TCP socket为例:

为对话框类添加一个socket类型的成员变量: SOCKET socketrecv;

然后在OnInitDialog()函数中添加以下代码:

   socketrecv=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,0);  

//WSASocket函数是用于创建套接字的扩展函数,与socket函数相比多了后面三个参数,从而使他比socket函数拥有更强大功能,如果不需要用到后三个参数新增的功能,可以直接使用socket函数创建套接字,作用一样。
   if(INVALID_SOCKET==socketrecv)
    {
        closesocket(socketrecv);
        MessageBox("套接字创建失败!");
        return FALSE;
    }

    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY); //本机任意IP地址
    addrSrv.sin_family=AF_INET;
    addrSrv.sin_port=htons(6500); //6500端口
    
    int ret1;
    ret1=bind(socketrecv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); //绑定套接字
    if(SOCKET_ERROR==ret1)
    {closesocket(socketrecv);
     MessageBox("套接字绑定失败!");
     return FALSE;
    }

    int ret2;
    ret2=listen(socketrecv,5);                    //开始监听
    if(SOCKET_ERROR==ret2)
    {
        closesocket(socketrecv);
        MessageBox("套接字监听失败!");
        return FALSE;
    }

    if(SOCKET_ERROR==WSAAsyncSelect(socketrecv,m_hWnd,UM_SOCK,FD_ACCEPT))
   {MessageBox("注册网络ACCEPT事件失败!");
   return FALSE;
   }

//WSAAsyncSelect函数用于请求一个网络事件通知,最后的参数是事件类型,本例注册了一个FD_ACCEPT事件,这样,当有socket 请求连接(connect)socketrecv的时候,就会触发FD_ACCEPT事件,系统就会发送UM_SOCK消息(UM_SOCK是用户自定义消息),后面必须在UM_SOCK消息的消息响应函数里进行socketrecv的accept操作。查看MSDN可查询到其他可以注册的网络事件类型。

3.UM_SOCK消息处理:

假定UM_SOCK消息的消息响应函数是void OnSock(WPARAM,LPARAM),注意这个消息响应函数的参数必须一定是(WPARAM,LPARAM)。然后void OnSock(WPARAM,LPARAM)的具体实现如下:

void CXXXDlg::OnSock(WPARAM wParam,LPARAM lParam)  

{
    switch(LOWORD(lParam))        //参数lParam包含了网络事件的类型
    { case FD_ACCEPT:

      if((SOCKET)wParam==socketrecv)    //参数wParam包含了消息是针对哪个socket发出的

        {

        SOCKADDR_IN addrconn;
          int len=sizeof(SOCKADDR);   
         socknec=accept(socketrecv,(SOCKADDR*)&addrconn,&len);  

          //开始接收连接,socknec是对话框类的一个socket类型成员变量,连接成功后负责与客户端socket收送数据
           if(INVALID_SOCKET ==socknec)        
           { closesocket(socknec);
            MessageBox("接收连接失败!");
              break;   //连接失败,跳出switch
           }

           break;    //连接成功,跳出switch

         }

    }

}

socket使用完毕后调用closesocket()函数关闭一个socket以回收资源。程序关闭前也必须使用WSACleanup函数终止对套接字库使用,注意必须在App类(应用程序类)的析构函数中调用WSACleanup函数。

以上的例子只是显示了对TCP socket的accept操作的异步处理,可以通过MSDN查询WSAAsyncSelect函数查看其他能进行异步处理的网络事件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值