GetMssage()和WSAAsyncSelect()捕獲網絡事件消息

1、GetMessage()函數說明 編程

要從消息隊列中取出消息,咱們須要調用GetMessage()函數,該函數的原型聲明以下: 網絡

BOOL GetMessage( socket

          LPMSG lpMsg,              // address of structure with message 函數

          HWND hWnd,                 // handle of window ui

          UINT wMsgFilterMin,       // first message spa

          UINT wMsgFilterMax        // last message 線程

); 指針

參數lpMsg指向一個消息(MSG)結構體,GetMessage從線程的消息隊列中取出的消息信息將保存在該結構體對象中。 對象

參數hWnd指定接收屬於哪個窗口的消息。一般咱們將其設置爲NULL,用於接收屬於調用線程的全部窗口的窗口消息。 接口

參數wMsgFilterMin指定要獲取的消息的最小值,一般設置爲0

參數wMsgFilterMax指定要獲取的消息的最大值。若是wMsgFilterMinwMsgFilter Max都設置爲0,則接收全部消息。

GetMessage函數接收到除WM_QUIT外的消息均返回非零值。對於WM_QUIT消息,該函數返回零。若是出現了錯誤,該函數返回-1,例如,當參數hWnd是無效的窗口句柄或lpMsg是無效的指針時。

 

2、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的消息,這是一個自定義的消息
而後再到消息循環中對這個消息進行響應就行了

3、使用方法

使用方法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     {         //;     } }

相關文章
相關標籤/搜索