WSAAsyncSelect模型

WSAAsyncSelect模型允许程序以windows消息的形式接受网络事件通知

WSAAsyncSelect函数自动把套接字设为非阻塞模式,并且为套接字绑定一个窗口句柄,当有网络事件发生时,便向这个窗口发送消息

int WSAAsyncSelect(
    SOCKET s, //套接字句柄
    HWND hWnd,//指定一个窗口句柄
    u_int wMsg,//网络事件到来的消息ID
    long lEvent//指定那些需要发送
);

FD_READ:接收对方发送的数据包

FD_WRITE:继续发送数据

FD_ACCEPT:有连接进入

FD_CONNECT:连接对方主机

FD_CLOSE:连接被关闭

调用WSAAsyncSelect函数监听套接字

::WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);

成功调用后,应用程序开始以windows消息形式在窗口函数接受网络事件通知

LRESULT CALLBACK WindowProc(HWND hWnd,
                            UINT uMsg,
                            WPARAM wParam,//发送网络事件的套接字句柄
                            LPARAM lParam//指定了发生的网络事件
);

下面是简单的TCP服务器程序,接受客户端的连接请求,打印出接收的数据。

// WSATCPSERVER.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h> 
#pragma comment(lib,"WS2_32")
class CInitSock
 {
 public:
     CInitSock(BYTE minorVer=2,BYTE majorVer=2)
     {
         WSADATA wsaData;
         WORD sockVersion = MAKEWORD(minorVer,majorVer);
         if(::WSAStartup(sockVersion,&wsaData)!=0)
         {
             exit(0);
         }
     }
     ~CInitSock()
     {
         ::WSACleanup();
     }
}; 
CInitSock initSock;
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
int _tmain(int argc, _TCHAR* argv[])
{
    char szClassName[] = "MainWClass";
    WNDCLASSEX wndclass;
    //用描述主窗口的参数填充WNDCLASSEX结构
    wndclass.cbSize = sizeof(wndclass);
    wndclass.style = CS_HREDRAW|CS_VREDRAW;
    wndclass.lpfnWndProc = WindowProc;
    wndclass.cbWndExtra = 0;
    wndclass.cbClsExtra = 0;
    wndclass.hInstance = NULL;
    wndclass.hIcon = ::LoadIcon(NULL,IDI_APPLICATION);
    wndclass.hCursor = ::LoadCursor(NULL,IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szClassName;
    wndclass.hIconSm = NULL;
    ::RegisterClassEx(&wndclass);
    //创建主窗口
    HWND hWnd = ::CreateWindowEx(
        0,
        szClassName,
        "",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        NULL,
        NULL);
    if(hWnd == NULL)
    {
        ::MessageBox(NULL,"创建窗口出错!","error",MB_OK);
        return -1;
    }
    USHORT nPort = 4567;
    SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(nPort);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;
    if(::bind(sListen,(sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR)
    {
         printf("Failed bind()\n");
         return -1;
    }
    //套接字设为窗口通知消息类型
    ::WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE);
    ::listen(sListen,5);
    //消息队列中取出消息
    MSG msg;
    while(::GetMessage(&msg,NULL,0,0))
    {
        ::TranslateMessage(&msg);//转化键盘消息
        ::DispatchMessage(&msg);//将消息发送到相应窗口函数
    }

    return msg.wParam;//当GETMESSAGE返回0时结束
}
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_SOCKET:
        {
            SOCKET s=wParam;
            //查看是否出错
            if(WSAGETSELECTERROR(lParam))
            {
                ::closesocket(s);
                return 0;
            }
            switch(WSAGETSELECTEVENT(lParam))
            {
            case FD_ACCEPT:
                {
                    SOCKET client = ::accept(s,NULL,NULL);
                    ::WSAAsyncSelect(client,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE);
                }
                break;
            case FD_WRITE:
                {

                }
                break;
            case FD_READ:
                {
                    char szText[1024]={0};
                    if(::recv(s,szText,1024,0) == -1)
                        ::closesocket(s);
                    else
                        printf("接收数据:%s",szText);
                }
                break;
            case FD_CLOSE:
                {
                    ::closesocket(s);
                }
                break;
            }
        }
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    }
    //不处理的消息交给系统默认处理
    return ::DefWindowProc(hWnd,uMsg,wParam,lParam);
}

好多错误啊...首先 char 不能转成LPSZ  其次,WM_SOCKET不认,为什么......哎

posted @ 2012-10-11 23:09 xingoo 阅读(...) 评论(...) 编辑 收藏