版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、網(wǎng)絡(luò)編程技術(shù),第8章 WinSock的I/O模型 (1),本次課內(nèi)容: 回顧阻塞和非阻塞套接字 WinSock 的I/O模型介紹 select 模型 WSAAsyncSelect 模型,8.1 套接字的阻塞和非阻塞操作,阻塞,阻塞的accept()操作,非阻塞的recv()操作,套接字I/O模型,問題:套接字何時可以進(jìn)行讀寫等操作? Winsock2提供5種I/O模型 選擇模型(select Model) 異步選擇模型(WSAAsyncSelect Model) 事件選擇模型(WSAEventSelect Model) 重疊模型(Overlapped Model) 完成端口模型(Complet
2、ion Port Model),非阻塞模式,WinSock給異步模式提供了五種I/O操作模型,可以靈活的用于各類應(yīng)用需求 非阻塞模式套接字除具備阻塞套接字已有的各項優(yōu)點之外,還進(jìn)行了少許擴(kuò)充,功能更強(qiáng)。,決定了,就用非阻塞的! How?,ioctlsocket()函數(shù)設(shè)置阻塞/非阻塞,創(chuàng)建套接字后,要將套接字設(shè)置為非阻塞,函數(shù): int ioctlsocket( SOCKET s, long cmd, u_long FAR *argp ); 用于設(shè)置和獲取與套接字相關(guān)的操作參數(shù)。 參數(shù) s: 套接字描述符。 cmd: 對套接字s的操作命令。 argp:指向cmd命令所帶參數(shù)的指針。 成功返回0
3、,否則,返回SOCKET_ERROR。,cmd FIONBIO:允許或禁止套接字s的非阻塞模式。 argp is zero,禁止非阻塞模式; argp is nonzero,允許非阻塞模式; 當(dāng)一個套接字建立時,默認(rèn)為阻塞模式; FIONREAD:確定套接字s可讀入的數(shù)據(jù)量。argp 指向一個無符號長整型。 如果s是SOCKET_STREAM類型,則FIONREAD返回在一次recv()中所接收的所有數(shù)據(jù)量。 如果s是SOCK_DGRAM 型,則FIONREAD返回套接字上排隊的第一個數(shù)據(jù)報大小。,ioctlsocket使用舉例,unsigned long mode=0; /禁止非阻塞 ioc
4、tlsocket(sockfd,FIONBIO,阻塞與非阻塞通信小結(jié) 通信包括阻塞和非阻塞兩種模式。在網(wǎng)絡(luò)編程時,選擇通信模式是一件很重要的事情。對于不同的協(xié)議,阻塞通信和非阻塞通信有不同的表現(xiàn)。 對于UDP協(xié)議而言,由于UDP沒有發(fā)送緩存,因此所有UDP協(xié)議即使在阻塞模式下也不會發(fā)生阻塞。 對于面向連接的協(xié)議,在連接建立階段,阻塞與非阻塞也表現(xiàn)不一。在阻塞模式下,如果沒有連接請求到達(dá),則等待連接調(diào)用將阻塞直到有連接請求到達(dá);但在非阻塞模式下,如果沒有連接請求到達(dá),等待連接調(diào)用將直接返回。,在連接建立階段,不管是阻塞模式還是非阻塞模式,發(fā)起連接請求的一方總是會使調(diào)用它的進(jìn)程阻塞,阻塞間隔最少等
5、于到達(dá)服務(wù)器的一次往返時間。 通信模式對應(yīng)用程序的設(shè)計方法也有直接的影響。在非阻塞模式下,應(yīng)用程序必須不斷地輪詢是否有數(shù)據(jù)到達(dá)或有連接請求到達(dá)。 這種輪詢的方式耗費的CPU資源較大,要盡可能避免使用,而在阻塞模式下則不存在這一問題,但其缺點是進(jìn)程或線程在執(zhí)行I/O操作時將被阻塞而不能執(zhí)行其他的工作,因此在單進(jìn)程或單線程應(yīng)用中不能使用這種模式。 在多線程應(yīng)用中比較適合采用阻塞模式,一個線程被阻塞不影響其他線程的工作。,8.2 套接字的I/O模型,套接字I/O模型,套接字處于非阻塞模式時,何時可以讀/寫套接字? 使用套接字I/O模型來確定 Winsock2提供5種I/O模型 選擇模型(select
6、 Model) 異步選擇模型(WSAAsyncSelect Model) 事件選擇模型(WSAEventSelect Model) 重疊模型(Overlapped Model) 完成端口模型(Completion Port Model),五種I/O模型的概述,選擇模型:程序自發(fā)select查詢多個套接字狀態(tài) 異步選擇模型:套接字有事件,通知指定窗口程序 事件選擇模型:套接字有事件,通知指定事件對象 重疊模型:提交多個I/O請求,完成后通知事件或執(zhí)行指定程序 完成端口模型:創(chuàng)建指定數(shù)目的線程,組成線程池,池內(nèi)的空閑線程對提交的I/O請求逐個處理。,操作系統(tǒng)對套接字I/O模型的支持情況,所有Win
7、dows平臺都支持套接字以阻塞或非阻塞方式工作。然而,并非每種平臺都支持每一種I/O模型。在當(dāng)前版本的Windows CE 中,僅提供了一個I/O模型。,套接字的select模型,select模型,select模型是WinSock中最常見的I/O模型。 程序調(diào)用select函數(shù)自發(fā)查詢一個或多個套接字的狀態(tài),判斷套接字上是否存在數(shù)據(jù),或者能否向一個套接字寫入數(shù)據(jù)。 既能防止應(yīng)用程序在套接字處于阻塞模式時,在一次I/O操作后被阻塞,同時也能防止在套接字處于非阻塞模式時,產(chǎn)生WSAEWOULDBLOCK錯誤。,select函數(shù)如下: int select( intnfds,/描述符值域,Windo
8、ws下可忽略 fd_set *readfds,/檢查可讀性集合 fd_set *writefds,/檢查可寫性集合 fd_set *exceptfds,/檢查錯誤集合 const struct timeval *timeout/等待時間);,select函數(shù)如下: int select( intnfds,/描述符值域,Windows下可忽略 fd_set *readfds,/檢查可讀性集合 fd_set *writefds,/檢查可寫性集合 fd_set *exceptfds,/檢查錯誤集合 const struct timeval *timeout/等待時間); fd_set 數(shù)據(jù)類型代表著
9、一系列特定套接字的集合。 typedef struct fd_set u_int fd_count; /反映fd_array的實際元素數(shù)量 SOCKET fd_arrayFD_SETSIZE; / 套接字句柄數(shù)組 fd_set;,此函數(shù)用于檢測一個或多個套接字的狀態(tài)。套接字的狀態(tài)包括可讀、可寫、出錯。 需要檢測狀態(tài)的套接字集合由一個fd_set結(jié)構(gòu)指示,分別為readfds,writefds,exceptfds(不能同時為NULL)。 參數(shù)timeout指向timeval結(jié)構(gòu),用于指定select等待I/O操作完成的時間。如timeout是一個空指針,select調(diào)用會無限期地,直到至少有一個
10、套接字滿足條件。,timeval結(jié)構(gòu)的格式為: struct timeval long tv_sec;/秒(s) long tv_usec;/毫秒(ms) ; select函數(shù)調(diào)用失敗,返回SOCKET_EEROR;超時返回0;成功返回所有集合中滿足條件的套接字?jǐn)?shù)量。同時傳入的套接字集合被更新,集合中保留滿足條件的套接字,readfds集合包括等待可讀性檢查的套接口: 有數(shù)據(jù)可以讀入。 連接已經(jīng)關(guān)閉、重設(shè)或中止。 偵聽套接字調(diào)用了listen(),若有連接請求到達(dá),那么accept函數(shù)調(diào)用會成功。 writefds集合包括等待可寫性檢查的套接口: 未處于connect()調(diào)用中,意味著send
11、()和sendto()調(diào)用可以無阻塞的發(fā)出數(shù)據(jù)。 如果正在connect()連接(非阻塞),可寫性意味著連接順利建立。 exceptfds集合包括滿足下述任何一個條件套接字: 假如套接口正在進(jìn)行connect()(非阻塞),則連接試圖的失敗將會表現(xiàn)在exceptfds參數(shù)中。 有帶外(Out-of-band,OOB)數(shù)據(jù)可供讀取。,readfds,writefds,exceptfds,套接字集合,有事情發(fā)生,有未決的連接請求,數(shù)據(jù)可讀,連接關(guān)閉/重啟/中斷,連接成功(connect),可寫數(shù)據(jù),連接失敗(connect),帶外數(shù)據(jù)可讀,選擇(select)模型處理方式,select(),假定想
12、測試一個套接字是否“可讀”,必須將該套接字增添到readfds集合,再等待select函數(shù)完成。 select完成之后,必須判斷該套接字是否仍在readfds集合中,若在,便表明該套接字“可讀”,可從它上面讀取數(shù)據(jù)。 Winsock提供了下列宏操作,對fd_set套接字集合進(jìn)行處理與檢查: FD_CLR(s, *set):從set中刪除套接字s。 FD_ISSET(s, *set):檢查s是否在set集合中,若是返回TRUE,否則返回FALSE。 FD_SET(s, *set):將套接字s加入集合set。 FD_ ZERO( * set ):將set初始化成空集合,使用select模型的編程步
13、驟: 建立fd_set集合s,用來存放待使用的套接字。 將套接字添加到集合s中。 確定要檢查的套接字集合Xi(1= i =3)。 使用FD_ZERO宏,初始化Xi 。 使用FD_SET宏,根據(jù)需要將套接字句柄添加到Xi中 調(diào)用select函數(shù) 根據(jù)select函數(shù)的返回值進(jìn)行處理,當(dāng)成功返回時,判斷s中套接字是否在Xi中,并進(jìn)行相應(yīng)處理 回到4,select模型實例分析,select模式實例,實現(xiàn)一個阻塞的TCP套接字服務(wù)器,端口5150; 主線程不斷的接受客戶端的連接; 工作線程利用 select() 函數(shù)不斷檢查是否有數(shù)據(jù)可以讀?。挥袆t讀取,原樣發(fā)送給客戶端。,select模式實例,/ 頭
14、文件 #include stdafx.h #include winsock2.h #include stdio.h #define PORT 5150 #define MSGSIZE 1024 #pragma comment(lib, ws2_32.lib) int g_iTotalConn = 0; /全局計數(shù)器 SOCKET g_CliSocketArrFD_SETSIZE; /全局通信套接字 DWORD WINAPI WorkerThread(LPVOID lpParam); /聲明處理數(shù)據(jù)接收的線程函數(shù),int main(int argc, char* argv) WSADATA ws
15、aData; SOCKET sListen, sClient; SOCKADDR_IN local, client; int iAddrSize = sizeof(SOCKADDR_IN); DWORD dwThreadId; / 初始化Winsock動態(tài)鏈接庫 WSAStartup(0 x0202, ,/ 綁定到IP和端口 local.sin_family = AF_INET; local.sin_addr.S_un.S_addr = htonl(INADDR_ANY); local.sin_port = htons(PORT); bind(sListen, (sockaddr*),whil
16、e (TRUE) / 接受客戶端連接 sClient = accept(sListen, (sockaddr*) ,DWORD WINAPI WorkerThread(LPVOID lpParam) int i; fd_set fdread; /定義一個FD集合,用于測試read int ret; struct timeval tv = 1, 0; /1秒的間隔 char szMessageMSGSIZE;/接收緩沖區(qū) while (TRUE) FD_ZERO( ,/ 我們只關(guān)心這些套接字里面有沒有數(shù)據(jù)可以read ret = select(0, ,if (ret = 0 | (ret = S
17、OCKET_ERROR /最后一個滿足條件的套接字放到i,將i、 g_iTotalConn減一, else /if (ret=) / ret0,沒出錯,收到ret個字節(jié) szMessageret = /0; send(g_CliSocketArri, szMessage, strlen(szMessage), 0); ,select模型的優(yōu)點:可以在單線程內(nèi)管理多個套接字,最大套接字?jǐn)?shù)量取決于FD_SETSIZE的大小,Winsock2.h中定義為64,用戶也可自行定義,但不能超過1024。 缺點:調(diào)用select前后對所有套接字都要進(jìn)行遍歷操作,以便設(shè)置和檢查。當(dāng)FD_SETSIZE太大時,
18、服務(wù)器性能明顯下降。,最通俗淺顯的“IO模式”解析,老陳有幾個在外地工作的女兒,不能經(jīng)?;貋?,老陳和她們通過信件聯(lián)系。她們的信會被郵遞員投遞到老陳的信箱里。 情況與Socket模型非常類似。,select模型,老陳非常想看到女兒的信。以至于他每隔10分鐘就下樓檢查信箱,看是否有女兒的信,在這種情況下,“下樓檢查信箱”然后回到樓上耽誤了老陳太多的時間,以至于老陳無法做其他工作。 select模型和老陳的這種情況非常相似:周而復(fù)始地去檢查.如果有數(shù)據(jù).接收/發(fā)送.,套接字的WSAAsyncSelect模型,WSAAsyncSelect模型,WSAAsyncSelect模型是WinSock中另一個常
19、用的異步I/O模型。 該模型可在套接字上接收以Windows消息為基礎(chǔ)的網(wǎng)絡(luò)事件通知。 調(diào)用WSAAsyncSelect函數(shù)自動將套接字設(shè)置為非阻塞模式,并向WinSock DLL注冊一個或多個感興趣的網(wǎng)絡(luò)事件,同時提供接收通知時使用的窗口句柄,當(dāng)注冊的網(wǎng)絡(luò)事件發(fā)生時,對應(yīng)的窗口將收到一個基于消息的通知。,WSAAsyncSelect函數(shù)如下: int WSAAPI WSAAsyncSelect( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );,s為需要事件通知的套接字,hWnd為接收消息的窗口句柄,wMsg為要接收的消息,lEve
20、nt為掩碼,指定應(yīng)用程序感興趣的網(wǎng)絡(luò)事件組合,用于WSAAsyncSelect函數(shù)的網(wǎng)絡(luò)事件類型,用法舉例,要接收讀寫通知: #define WM_SOCKET WM_USER + 101 int nResult = WSAAsyncSelect(s,hWnd,WM_SOCKET,FD_READ|FD_WRITE); if(nResult=SOCKET_ERROR) /錯誤處理 ,問題1:對監(jiān)聽套接字和通信套接字應(yīng)如何設(shè)置消息通知?設(shè)置哪些事件? 監(jiān)聽套接字: WSAAsyncSelect(sListen,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE); 通信套接字: W
21、SAAsyncSelect(sComm,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE);,注意: 多個事件務(wù)必在套接字上一次注冊! 一旦在某個套接字上允許了事件通知,除非以后明確調(diào)用closesocket(),或者由應(yīng)用程序針對該套接字調(diào)用了WSAAsyncSelect,從而更改了注冊的網(wǎng)絡(luò)事件類型,否則的話,事件通知會永遠(yuǎn)有效! 若將lEvent參數(shù)設(shè)為0,效果相當(dāng)于停止在套接字上進(jìn)行的所有網(wǎng)絡(luò)事件通知。,只接受一個消息設(shè)置.下面的代碼將不會工作;第二個調(diào)用將會使第一次調(diào)用的作用失效,只有FD_WRITE會通過wMsg2消息通知到。 1、 WSAAsync
22、Select(s, hWnd, wMsg1, FD_READ);2、 WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE); 如果要取消所有的通知,也就是指出Windows Sockets的實現(xiàn)不再在套接口上發(fā)送任何和網(wǎng)絡(luò)事件相關(guān)的消息,則lEvent應(yīng)置為0. WSAAsyncSelect(s, hWnd, 0, 0);,應(yīng)用程序在一個套接字上成功調(diào)用了WSAAsyncSelect之后,應(yīng)用程序會在與hWnd窗口句柄參數(shù)對應(yīng)的窗口處理函數(shù)中,以Windows消息的形式,接收網(wǎng)絡(luò)事件通知。 窗口處理函數(shù)定義如下:,LRESULT CALLBACK WindowPro
23、c(HWND hwhd, UINT uMsg, WPARAM wParam, LPARAM IParam) 參數(shù): hwnd:指向窗口的句柄。 uMsg:指定消息類型。 wParam:指定消息的附加信息。該參數(shù)的內(nèi)容與UMsg參數(shù)值有關(guān)。 IParam:指定消息的附加信息。該參數(shù)的內(nèi)容與uMsg參數(shù)值有關(guān)。 返回值:返回值就是消息處理結(jié)果,它與發(fā)送的消息有關(guān)。,wParam, IParam參數(shù)在uMsg WM_SOCKET時的含義: wParam指定發(fā)生網(wǎng)絡(luò)事件的套接字。 IParam指定發(fā)生的網(wǎng)絡(luò)事件和錯誤代碼。 其中高字位指出網(wǎng)絡(luò)錯誤。采用宏:WSAGETSELECTERROR,可用它返回
24、高字節(jié)包含的錯誤信息,如下: #define WSAGETSELECTERROR(lParam) HIWORD(lParam) 低字位指出發(fā)生的網(wǎng)絡(luò)事件,采用宏:WSAGETSELECTEVENT,返回網(wǎng)絡(luò)事件 #define WSAGETSELECTEVENT(lParam) LOWORD(lParam),收到 FD_READ 事件通知的情況: (1)調(diào)用 WSAAsyncSelect ()對 socket 設(shè)定 FD_READ 事件時,接收緩沖區(qū)中已有數(shù)據(jù)。 (2)接收緩沖區(qū)由空變?yōu)橛袛?shù)據(jù) (3)調(diào)用 recv() 或 recvfrom ()從 接收緩沖區(qū)讀取數(shù)據(jù)時沒有讀完。,收到FD_W
25、RITE事件通知的情況: 使用connect或WSAConnect,一個套接字首次建立了連接。 使用accept或WSAAccept,套接字被接受以后。 若send、WSASend、sendto或WSASendTo操作失敗,返回了WSAEWOULDBLOCK錯誤,而且緩沖區(qū)的空間變得可用。 應(yīng)用程序,自收到首條FD_WRITE消息開始,便應(yīng)認(rèn)為自己必然能在一個套接字上發(fā)出數(shù)據(jù),直至一個send、WSASend、sendto或WSASendTo返回套接字錯誤WSAEWOULDBLOCK。經(jīng)過了這樣的失敗以后,系統(tǒng)要再用另一條FD_WRITE通知應(yīng)用程序再次發(fā)送數(shù)據(jù)。,使用WSAAsyncSele
26、ct模型編程步驟: Winsock初始化 自定義WM_SOCKET 消息 創(chuàng)建窗口,必須有窗體才有消息處理 創(chuàng)建套接字 調(diào)用WSAAsyncSelect()定義需要響應(yīng)的Socket動作 編寫WindowProc()完成Socket相關(guān)動作處理,示例:WSAAsyncSelect模式的服務(wù)器,#pragma once #include #include #define PORT 5150 #define MSGSIZE 1024 #define WM_SOCKET WM_USER+0 #pragma comment(lib, ws2_32.lib) LRESULT CALLBACK WndPr
27、oc(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 的風(fēng)格定義 if (!RegisterClass( ,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
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年合肥科技職業(yè)學(xué)院高職單招職業(yè)適應(yīng)性考試模擬試題帶答案解析
- 醫(yī)院志愿者服務(wù)標(biāo)準(zhǔn)
- 心理護(hù)理對抑郁患者的干預(yù)
- 醫(yī)療保險市場分析與趨勢
- 2026年河南建筑職業(yè)技術(shù)學(xué)院單招職業(yè)技能筆試參考題庫帶答案解析
- 心臟重癥患者護(hù)理實踐與探討
- 2026年川北幼兒師范高等專科學(xué)校單招綜合素質(zhì)筆試備考題庫帶答案解析
- 2026年黑龍江護(hù)理高等專科學(xué)校高職單招職業(yè)適應(yīng)性測試備考題庫有答案解析
- 醫(yī)療信息化安全與合規(guī)性
- 財務(wù)顧問課件
- 2026年廣西貴港市華盛集團(tuán)新橋農(nóng)工商有限責(zé)任公司招聘備考題庫及答案詳解1套
- 陜西能源職業(yè)技術(shù)學(xué)院2026年教師公開招聘備考題庫完整答案詳解
- 綠化苗木種植合同范本
- 2026年遼寧省沈陽市單招職業(yè)傾向性測試題庫及參考答案詳解一套
- 冶金原理李洪桂課件
- 2025年南京市導(dǎo)游綜合知識問答題庫及答案
- 2026《初中英語?優(yōu)翼學(xué)練優(yōu)》八上早讀本
- GB/T 1301-2025鑿巖釬桿用中空鋼
- 關(guān)于安吉物流市場的調(diào)查報告
- 抑郁病診斷證明書
- 歷史時空觀念的教學(xué)與評價
評論
0/150
提交評論