█ 非同步選擇(wsaasyncselect)模型是乙個有用的非同步 i/o 模型。利用這個模型,應用程式可在乙個套接字上,
接收以 windows 訊息為基礎的網路事件通知。具體的做法是在建好乙個套接字後,呼叫wsaasyncselect函式。
該模型的核心即是wsaasyncselect函式。
█ 要想使用 wsaasyncselect 模型,在應用程式中,首先必須用createwindow函式建立乙個視窗,再為該視窗提供乙個視窗例程函式(winproc)。
█ wsaasyncselect 的函式原型如下:
int wsaasyncselect(
__in socket s,
__in hwnd hwnd,
__in unsigned int wmsg,
__in long levent
);
● s 引數指定的是我們感興趣的那個套接字。
● hwnd 引數指定乙個視窗控制代碼,它對應於網路事件發生之後,想要收到通知訊息的那個視窗。
● wmsg 引數指定在發生網路事件時,打算接收的訊息。該訊息會投遞到由hwnd視窗控制代碼指定的那個視窗。
(通常,應用程式需要將這個訊息設為比windows的wm_user大的乙個值,避免網路視窗訊息與系統預定義的標準視窗訊息發生混淆與衝突)
● levent 引數指定乙個位掩碼,對應於一系列網路事件的組合,大多數應用程式通常感興趣的網路事件型別包括:
fd_read、fd_write、fd_accept、fd_connect、fd_close。當然,到底使用fd_accept,還是使用fd_connect型別,
要取決於應用程式的身份是客戶端,還是伺服器。如應用程式同時對多個網路事件有興趣,只需對各種型別執行一次簡單的按位or(或)運算,
然後將它們分配給levent就可以了,例如:
wsaasyncseltct(s, hwnd, wm_socket, fd_connect | fd_read | fd_write | fd_close);
解釋說明:我們的應用程式以後便可在套接字s上,接收到有關連線、傳送、接收以及套接字關閉這一系列網路事件的通知。
█ 注意 ①:
多個事件務必在套接字上一次註冊!
另外還要注意的是,一旦在某個套接字上允許了事件通知,那麼以後除非明確呼叫closesocket命令,
或者由應用程式針對那個套接字呼叫了wsaasyncselect,從而更改了註冊的網路事件型別,否則的話,
事件通知會永遠有效!若將levent引數設為0,效果相當於停止在套接字上進行的所有網路事件通知。
█ 注意 ②:
若應用程式針對乙個套接字呼叫了wsaasyncselect,那麼套接字的模式會從「鎖定」變成「非鎖定」。
這樣一來,如果呼叫了像wsarecv這樣的winsock函式,但當時卻並沒有資料可用,那麼必然會造成呼叫的失敗,並返回wsaewouldblock錯誤。
為防止這一點,應用程式應依賴於由wsaasyncselect的umsg引數指定的使用者自定義視窗訊息,來判斷網路事件型別何時在套接字上發生;而不應盲目地進行呼叫。
fd_read
應用程式想要接收有關是否可讀的通知,以便讀入資料
fd_write
應用程式想要接收有關是否可寫的通知,以便寫入資料
fd_accept
應用程式想接收與進入連線有關的通知
fd_connect
應用程式想接收與一次連線完成的通知
fd_close
應用程式想接收與套接字關閉的通知
█ 應用程式在乙個套接字上成功呼叫了wsaasyncselect之後,會在與hwnd視窗控制代碼對應的視窗例程中,以windows訊息的形式,接收網路事件通知。
視窗例程通常定義如下:
lresult callback windowproc(
hwnd hwnd,
uint umsg,
wparam wparam,
lparam lparam
);
● hwnd 引數指定乙個視窗的控制代碼,對視窗例程的呼叫正是由那個視窗發出的。
● umsg 引數指定需要對哪些訊息進行處理。這裡我們感興趣的是wsaasyncselect呼叫中定義的訊息。
● wparam 引數指定在其上面發生了乙個網路事件的套接字。假若同時為這個視窗例程分配了多個套接字,這個引數的重要性便顯示出來了。
● lparam引數中,包含了兩方面重要的資訊。其中, lparam的低字(低位字)指定了已經發生的網路事件,而lparam的高字(高位字)包含了可能出現的任何錯誤**。
█ 步驟:網路事件訊息抵達乙個視窗例程後,應用程式首先應檢查lparam的高字位,以判斷是否在網路錯誤。
這裡有乙個特殊的巨集: wsagetselecterror,可用它返回高字位包含的錯誤資訊。
若應用程式發現套接字上沒有產生任何錯誤,接著便應調查到底是哪個網路事件型別,具體的做法便是讀取lparam低字位的內容。
此時可使用另乙個特殊的巨集:wsagetselectevent,用它返回lparam的低字部分。
█ 注意 ③:應用程式如何對 fd_write 事件通知進行處理。
只有在三種條件下,才會發出 fd_write 通知:
■ 使用 connect 或 wsaconnect,乙個套接字首次建立了連線。
■ 使用 accept 或 wsaaccept,套接字被接受以後。
■ 若 send、wsasend、sendto 或 wsasendto 操作失敗,返回了 wsaewouldblock 錯誤,而且緩衝區的空間變得可用。
因此,作為乙個應用程式,自收到首條 fd_write 訊息開始,便應認為自己必然能在乙個套接字上發出資料,
直至乙個send、wsasend、sendto 或 wsasendto 返回套接字錯誤 wsaewouldblock。
經過了這樣的失敗以後,要再用另一條 fd_write 通知應用程式再次傳送資料。
用例:
wsaasyncselect(pthis->m_socklisten, pthis->getsafehwnd(), wm_socket, fd_accept | fd_close);//wm_socket為自定義訊息#define wm_socket wm_user+100
//override視窗過程函式
lresult cserverdlg::windowproc(uint message, wparam wparam, lparam lparam)
break;
case wm_socket:
if (wsagetselecterror(lparam))
switch(wsagetselectevent(lparam))
m_sockclient = accept(wparam, null, null);
wsaasyncselect(m_sockclient, m_hwnd, wm_socket, fd_read|fd_write|fd_close);
++m_clientnums;
break;
}case fd_read:
;recv(wparam, (char *)szbuf, max_buf_size, 0);
showmsg(szbuf);
break;
}case fd_write:
wparam = wparam;
break;
case fd_close:
--m_clientnums;
closesocket(wparam);
break;
} default:break;
} return cdialog::windowproc(message, wparam, lparam);
}
非同步選擇模型
非同步選擇 wsaasyncselect 模型是乙個有用的非同步 i o 模型。利用這個模型,應用程式可在乙個套接字上,接收以 windows 訊息為基礎的網路事件通知。具體 的做法是在建好乙個套接字後,呼叫wsaasyncselect函式。該模型的核心即是wsaasyncselect函式。wsaa...
非同步選擇模型
非同步選擇 wsaasyncselect 模型是乙個有用的非同步 i o 模型。利用這個模型,應用程式可在乙個套接字上,接收以 windows 訊息為基礎的網路事件通知。具體 的做法是在建好乙個套接字後,呼叫wsaasyncselect函式。該模型的核心即是wsaasyncselect函式。wsaa...
socket模型 非同步事件選擇模型的正常退出
今天要用到非同步事件選擇模型,發現demo原型不能正常退出.除錯了一下,用wsasetevent waitforsingleobject 全域性標記搞定.如果以後要用到非同步事件選擇模型,在這個demo上直接加業務邏輯.srcasynceventselect.zip include stdafx.h...