windows socket I/O模型之WSAAsyncSelect模型(異步IO模型)

當前Windows支持的各種Socket I/O模型,主要的模型如下:

    一:select模型

    二:WSAAsyncSelect模型

    三:WSAEventSelect模型

    四:Overlapped I/O 事件通知模型

    五:Overlapped I/O 完成例程模型

    六:IOCP模型

其中本文主要講解WSAAsyncSelect模型,以一種無線通信信令模擬軟件的客戶端程序爲例子,模擬軟件是服務器軟件和客戶端軟件組成,採用TCP通信。對於客戶端程序來說,由於傳輸的數據量不大,只開啓一個socket與服務器端進行通信,可以採用WSAAsyncSelect模型,這樣可以避免採用線程方式的同步問題。WSAAsyncSelect模型是Windows下最簡單易用的一種Socket I/O模型。利用這個模型,應用程序可在一個套接字上,接收以Windows消息爲基礎的網絡事件通知。其優缺點如下:

優點:可在系統開銷不大的情況下同時處理許多連接。

缺點:即使用不需要窗口(如服務器,控制檯)它也不得不額外使用一個窗口。同時如果處理成千上萬套接字的所有事件,性能可想而知。

MFCCSocket所使用的正是這種事件通知模型,要想使用WSAAsyncSelect模型,在應用程序中,首先必須用CreateWindow函數創建一個窗口,再爲該窗口提供一個窗口例程支持函數(Winproc)。亦可使用一個對話框,爲其提供一個對話例程,而非窗口例程,因爲對話框本質也是“窗口”。

本例子用MFC的對話框模式,以對話框爲窗口例程,窗口例程消息處理函數來處理socket的觸發事件。具體的做法如下:

1.初始化socket通信環境。

具體對話框實例爲CTKClientDlg,在CTKClientDlg::OnInitDialog()函數中調用WSAStartup()函數初始化,如下:

WORD wVersionRequested;

WSADATA wsaData;

int err;                                       

wVersionRequested = MAKEWORD( 2, 2 );

err = WSAStartup( wVersionRequested, &wsaData );

if ( err != 0 )

{

return FALSE;

}

if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )

 {

WSACleanup( );

return FALSE;

}

2.建立一個套接字後,調用WSAAsyncSelect函數。可以在一個按鈕的消息處理函數中添加如下:

void CTKClientDlg::OnButConn()

{

//創建套接字

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

  if(INVALID_SOCKET==m_Socket)

  {

                                                           return TK_FAILED;

  }

//服務器地址信息

  SOCKADDR_IN addrSock;

  addrSock.sin_addr.S_un.S_addr=htonl(dwAddr);

  addrSock.sin_family=AF_INET;

  addrSock.sin_port=htons(iPort);

//連接服務器

  if(SOCKET_ERROR==connect(m_Socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR)))

  {

                                                           closesocket(m_Socket);

                                                           return TK_FAILED;

  }

//註冊網絡事件

  if(SOCKET_ERROR==WSAAsyncSelect(m_Socket,hWnd,UM_SOCK,FD_READ | FD_CLOSE))

  {

                                                           closesocket(m_Socket);

                                                           return TK_FAILED;

  }

  return TK_SUCCESS;

}

以上一個比較重要的函數是 WSAAsyncSelect (),這個函數用於註冊窗口要處理的網絡事件,已經網絡事件發生時向窗口發送的用戶的消息。在WSAAsyncSelect(m_Socket,hWnd,UM_SOCK,FD_READ | FD_CLOSE))

函數中,註冊了socket接收到數據和socket關閉時觸發的事件消息。這兩個網絡事件分別用FD_READFD_CLOSE註冊,類似的網絡時間還有FD_WRITE FD_OOB FD_ACCEPT FD_CONNECT。對應一系列網絡事件的組合,

Event 含義

FD_READ 程序想要接收有關是否可讀的通知,以便讀入數據

FD_WRITE 程序想要接收有關是否可寫的通知,以便寫入數據

FD_OOB 程序想要接收是否有OOB數據到達的通知

FD_ACCEPT 程序想要接收與進入連接有關的通知

FD_CONNECT 程序想要接收與一次連接或多點接入有關的通知

FD_CLOSE 程序想要接收與套接字關閉有關的通知

FD_QOS 程序想要接收套接字“服務質量(QoS)”發生變化的通知

FD_GROUP_QOS 暫時沒用,屬於保留事件

FD_ROUTING_INTERFACE_CHANGE 程序想要接收有關到指定地址的路由接口發生變化的通知

FD_ADDRESS_LIST_CHANGE 程序想要接收本地地址變化的通知

UM_SOCK爲註冊的消息參數標量,

//自定義消息

#define UM_SOCK        WM_USER + 1

3.映射消息處理函數,並實現消息處理函數,映射如下:

BEGIN_MESSAGE_MAP(CTKClientDlg, CDialog)

           ON_MESSAGE(UM_SOCK, OnSock)

           ON_MESSAGE(UM_DISP, OnDisplayMsg)

           ON_MESSAGE(UM_RELEASE, OnRelease)

END_MESSAGE_MAP()

以上是將UM_SOCK消息和OnSock函數進行了關聯。

定義消息處理函數,在CTKClientDlg類定義如下:

DECLARE_MESSAGE_MAP()

afx_msg void OnSock(WPARAM,LPARAM);

 

實現消息處理函數如下:

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

{

                                                           switch(LOWORD(lParam))

                                                           {

                                                           case FD_READ:

                                                             {

                   //socket收到數據的處理代碼

                                                             }      

                                                             break;

                                                           case FD_CLOSE:

                                                             {

                  //socket關閉時的處理代碼

                                                             }

                                                             break;

                                                           default:

                                                             break;

                                                           }

}

 

最後感謝高成eason提供代碼。

發佈了28 篇原創文章 · 獲贊 3 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章