GetMssage()和WSAAsyncSelect()捕获网络事件消息

一、GetMessage()函数说明

要从消息队列中取出消息,我们需要调用GetMessage()函数,该函数的原型声明如下:

BOOL GetMessage(

          LPMSG lpMsg,              // address of structure with message

          HWND hWnd,                 // handle of window

          UINT wMsgFilterMin,       // first message

          UINT wMsgFilterMax        // last message

);

参数lpMsg指向一个消息(MSG)结构体,GetMessage从线程的消息队列中取出的消息信息将保存在该结构体对象中。

参数hWnd指定接收属于哪一个窗口的消息。通常我们将其设置为NULL,用于接收属于调用线程的所有窗口的窗口消息。

参数wMsgFilterMin指定要获取的消息的最小值,通常设置为0

参数wMsgFilterMax指定要获取的消息的最大值。如果wMsgFilterMinwMsgFilter Max都设置为0,则接收所有消息。

GetMessage函数接收到除WM_QUIT外的消息均返回非零值。对于WM_QUIT消息,该函数返回零。如果出现了错误,该函数返回-1,例如,当参数hWnd是无效的窗口句柄或lpMsg是无效的指针时。

 

二、WSAAsyncSelect()函数

 Windows消息机制编写socket客户端程序的方法。使用Windows消息机制编写socket程序主要有以下的好处:一是我们可以将大部分的recv操作以及close操作放到消息处理函数里面,以利于代码的维护;二是当有数据可读的时候,本地程序会接到相应的消息,我们可以在这时候读取数据。

WSAAsyncSelect(?)是Winsock提供的一个适合于Windows编程使用的函数,它允许在一个套接口上当发生特定的网络事件时,给Windows网络应用程序(窗口或对话框)发送一个消息(事件通知)。


这是一种winsock下的网络模型
例如: int iErrorCode=WSAAsyncSelect(mySocket.m_clientSocket,m_hWnd,WM_CLIENT_READ,FD_READ | FD_CLOSE);
这样一句代码,它告诉系统,现在我这个mySocket.m_clientSocket,只关注FD_READ | FD_CLOSE两个网络事件,一旦有这两个事件,我就会投递一个WM_CLIENT_READ的消息,这是一个自定义的消息
然后再到消息循环中对这个消息进行响应就好了

三、使用方法

使用方法1:

#pragma once 
#include <winsock.h>
#include <tchar.h>
#define PORT 5150
#define MSGSIZE 1024
#define WM_SOCKET WM_USER+0
#pragma comment(lib, "ws2_32.lib")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
 static TCHAR szAppName[] = _T("AsyncSelect Model");
 HWND hwnd ;
 MSG msg ;
 WNDCLASS wndclass ;
 wndclass.style = CS_HREDRAW | CS_VREDRAW ;  //可以0
 wndclass.lpfnWndProc = WndProc ;   //事件处理
 wndclass.cbClsExtra = 0 ;
 wndclass.cbWndExtra = 0 ;
 wndclass.hInstance = hInstance ;
 wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
 wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 wndclass.lpszMenuName = NULL ;
 wndclass.lpszClassName = szAppName ;
 if (!RegisterClass(&wndclass))           //注册窗体类
 {
  MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;
  return 0 ;
 }
 hwnd = CreateWindow (szAppName, // window class name

  TEXT ("AsyncSelect Model"), // window caption

  WS_OVERLAPPEDWINDOW, // window style

  CW_USEDEFAULT, // initial x position

  CW_USEDEFAULT, // initial y position

  CW_USEDEFAULT, // initial x size

  CW_USEDEFAULT, // initial y size

  NULL, // parent window handle

  NULL, // window menu handle

  hInstance, // program instance handle

  NULL) ; // creation parameters

 ShowWindow(hwnd, iCmdShow);
 UpdateWindow(hwnd);
 while (GetMessage(&msg, NULL, 0, 0) != 0)
 {
  TranslateMessage(&msg) ;
  DispatchMessage(&msg) ;
 }
 return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 WSADATA wsd;
 static SOCKET sListen;
 SOCKET sClient;
 SOCKADDR_IN local, client;
 int ret, iAddrSize = sizeof(client);
 char szMessage[MSGSIZE];
 switch (message)
 {
 case WM_CREATE:
  // Initialize Windows Socket library

  WSAStartup(0x0202, &wsd);
  // Create listening socket

  sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  // Bind

  local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
  local.sin_family = AF_INET;
  local.sin_port = htons(PORT);
  bind(sListen, (struct sockaddr *)&local, sizeof(local));
  // Listen

  listen(sListen, 3);
  // Associate listening socket with FD_ACCEPT event

  WSAAsyncSelect(sListen, hwnd, WM_SOCKET, FD_ACCEPT);
  return 0;
 case WM_DESTROY:
  closesocket(sListen);
  WSACleanup();
  PostQuitMessage(0);
  return 0;
 case WM_SOCKET:
  if (WSAGETSELECTERROR(lParam))
  {
   closesocket(wParam);
   break;
  }
  switch (WSAGETSELECTEVENT(lParam))
  {
  case FD_ACCEPT:
   // Accept a connection from client

   sClient = accept(wParam, (struct sockaddr *)&client, &iAddrSize);
   // Associate client socket with FD_READ and FD_CLOSE event

   WSAAsyncSelect(sClient, hwnd, WM_SOCKET, FD_READ | FD_CLOSE);
   break;
  case FD_READ:
   ret = recv(wParam, szMessage, MSGSIZE, 0);
   if (ret == 0 || ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
   {
    closesocket(wParam);
   }
   else
   {
    szMessage[ret] = '\0';
    send(wParam, szMessage, strlen(szMessage), 0);
   }
   break;
  case FD_CLOSE:
   closesocket(wParam); 
   break;
  }
  return 0;
 }
 return DefWindowProc(hwnd, message, wParam, lParam);
}

使用方法2:

        WNDCLASSEX theWndClass;
        theWndClass.cbSize = sizeof(theWndClass);
        theWndClass.style = 0;
        theWndClass.lpfnWndProc = &select_wndproc;
        theWndClass.cbClsExtra = 0;
        theWndClass.cbWndExtra = 0;
        theWndClass.hInstance = NULL;
        theWndClass.hIcon = NULL;
        theWndClass.hCursor = NULL;
        theWndClass.hbrBackground = NULL;
        theWndClass.lpszMenuName = NULL;
        theWndClass.lpszClassName = "ServerWindow";
        theWndClass.hIconSm = NULL;
       
        ATOM theWndAtom = ::RegisterClassEx(&theWndClass);  //注册一个窗口类
        Assert(theWndAtom != NULL);
        if (theWndAtom == NULL)
            ::exit(-1);
                
        sMsgWindow = ::CreateWindow(    "ServerWindow",  // Window class name
                                        "ServerWindow",  
                                        WS_POPUP, 
                                        0,          // x pos
                                        0,          // y pos
                                        CW_USEDEFAULT,  
                                        CW_USEDEFAULT,  
                                        NULL,     
                                        NULL,        
                                        NULL,           
                                        NULL);         
        Assert(sMsgWindow != NULL);
        if (sMsgWindow == NULL)
            ::exit(-1);
    }

    MSG theMessage; 

    //函数GetMessage 是 从调用线程的消息队列里取得一个消息并将其放于指定的结构
    UInt32 theErr = ::GetMessage(&theMessage, sMsgWindow, 0, 0);  //阻塞 一直等待消息到来才返回


    if (theErr > 0)
    {
        UInt32 theSelectErr = WSAGETSELECTERROR(theMessage.lParam);
        UInt32 theEvent = WSAGETSELECTEVENT(theMessage.lParam);
       
        req->er_handle = theMessage.wParam; 
        req->er_eventbits = EV_RE;          
        req->er_data = (void*)(theMessage.message);

        (void)::WSAAsyncSelect(req->er_handle, sMsgWindow, 0, 0); 

  return 0;                       }
    else
    {

        //;
    }
}

 

你可能感兴趣的:(GetMssage()和WSAAsyncSelect()捕获网络事件消息)