MFC_IO模型_异步选择模型WSAAsyncSelect

先来说下什么是异步WSAAsyncSelect模型,异步WSAAsyncSelect模型说白了,就是让系统帮咱们去监听咱们服务器上的一个socket

 

系统会帮我们监听客户端的连接,客户端的断开,客户端的发送数据,等等,

一般,这种模型适用与窗口模型,先来讲讲他如何使用:

1.在创建完窗口的时候,顺便把socket也一起创建了吧,在把咱们的socket交给系统处理(让他我们监听咱们socket的消息,比如客户端连接,断开这些啊,就不用咱们人为的去判断了)

2.重写消息函数,也就是窗口回调函数,里面判断message的消息是否是咱们自定义的消息,然后在判断处理,

3.重写消息函数,拦截WM_DESTROY 消息,对咱们服务端的socket进行关闭和清理socket网络环境

下面看实例:

void Cselect服务端Dlg::OnBnClickedButton1()
{
    WSADATA     wsaData;

    int         iaddrSize = sizeof(SOCKADDR_IN);
    DWORD       dwThreadId;
    // Initialize Windows socket library
    //装载套接字库
    WSAStartup(0x0202, &wsaData);
    // Create listening socket
    //创建套接字
    sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    // Bind
    //绑定
    CString ip;
    this->GetDlgItemText(IDC_EDIT5,ip);
    USES_CONVERSION;
    local.sin_addr.S_un.S_addr = inet_addr(W2A(ip.GetBuffer()));
    ip.ReleaseBuffer();
    local.sin_family = AF_INET;
    this->GetDlgItemText(IDC_EDIT2,ip);
    local.sin_port = htons(_tstoi(ip.GetBuffer()));
    ip.ReleaseBuffer();
    bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));
    // Listen
    //监听
    listen(sListen, 1000);
    AfxMessageBox(_T("监听成功"));
    iAddrSize = sizeof(SOCKADDR_IN);
    WSAAsyncSelect(sListen,this->GetSafeHwnd() , WM_SOCKET, FD_ACCEPT);//第一个参数为需要监听的socket,第二个为窗口句柄,第三个是咱们定义的消息类型,第四个为感兴趣的东西


}



LRESULT Cselect服务端Dlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    
    switch(message){
case WM_DESTROY:
    closesocket(sListen);//这个就是关闭socket了撒
    WSACleanup();//清理环境,这个就不用说了吧?
    PostQuitMessage(0);//给系统发送一个消息,就是关闭窗体,也可以重写窗口的destory方法,也可以拦截这个消息,其实默认的destory方法里面就是给窗口发送了一个postmessage消息
    return 0;

case WM_SOCKET://我们的消息来了吧?
    if (WSAGETSELECTERROR(lParam))//判断是否socket有异常,有异常还搞个P啊,直接关闭socket
    {
        closesocket(wParam);//wParam其实就是客户端的socket
        break;
    }

    switch (WSAGETSELECTEVENT(lParam))//WSAGETSELECTEVENT其实就是一个宏,记住他可以判断socket是什么消息就好了
    {
    case FD_ACCEPT://如果有客户端连接到来的话
        // Accept a connection from client
        
        sClient = accept(wParam, (struct sockaddr *)&client, &iAddrSize);//咱们就接受他,sClient就是咱们客户端,wParam就是咱们的服务端

        // Associate client socket with FD_READ and FD_CLOSE event
        WSAAsyncSelect(sClient, this->GetSafeHwnd(), WM_SOCKET, FD_READ | FD_CLOSE);//加入到异步选择的容器中,系统自动帮我们管理
        break;
    case FD_READ:
        char buff[1024];
        ret = recv(wParam, buff, sizeof(buff), 0);//这时候wParam就是客户端了
        if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
        {
            closesocket(wParam);
        }
        else
        {
            buff[ret] = '\0';
            send(wParam, buff, strlen(buff)*sizeof(char), 0);
        }
        break;

    case FD_CLOSE:
        closesocket(wParam);//如果是客户端关闭的话
        break;
    }
    }
    return CDialog::WindowProc(message, wParam, lParam);
}

在给大家说一个小技巧,如何停止系统对咱们服务端上socket的监听呢?

 WSAAsyncSelect(sListen,0 ,0);

把监听的窗口句柄改为0就好了

posted @ 2013-08-10 11:32  宝贝,我永远都在  阅读(1023)  评论(0)    收藏  举报