第18章 客戶—服務(wù)器模型_第1頁
第18章 客戶—服務(wù)器模型_第2頁
第18章 客戶—服務(wù)器模型_第3頁
第18章 客戶—服務(wù)器模型_第4頁
第18章 客戶—服務(wù)器模型_第5頁
已閱讀5頁,還剩75頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、第18章 客戶服務(wù)器模型第18章 客戶服務(wù)器模型 18.1 基本模型18.1.1 面向連接與無連接18.1.2 并發(fā)和迭代18.2 Winsock I/O模型18.2.1 I/O復(fù)用-select18.2.2 消息機(jī)制-WSAAsyncSelect18.2.3 事件機(jī)制-WSAEventSelect18.2.4 重疊I/0模型18.2.5 I/O完成端口IOCP18.1 基本模型在TCP/IP網(wǎng)絡(luò)中兩個進(jìn)程間的相互作用的主機(jī)模式是客戶機(jī)客戶機(jī)/ /服務(wù)器模式服務(wù)器模式(Client/Server model)。該模式的建立基于以下兩點(diǎn):l非對等作用;l通信完全是異步的??蛻魴C(jī)/服務(wù)器模式在操作

2、過程中采取的是主動請示方式: 18.1 基本模型首先服務(wù)器方服務(wù)器方要先啟動,并根據(jù)請示提供相應(yīng)服務(wù):1、打開一通信通道并告知本地主機(jī),它愿意在某一個公認(rèn)地址上接收客戶請求。2、等待客戶請求到達(dá)該端口。3、接收到重復(fù)服務(wù)請求,處理該請求并發(fā)送應(yīng)答信號。4、返回第二步,等待另一客戶請求5、關(guān)閉服務(wù)器。18.1 基本模型客戶方客戶方:1、打開一通信通道,并連接到服務(wù)器所在主機(jī)的特定端口。2、向服務(wù)器發(fā)送服務(wù)請求報(bào)文,等待并接收應(yīng)答;繼續(xù)提出請求3、請求結(jié)束后關(guān)閉通信通道并終止。 18.1.1 面向連接與無連接可以是基于連接的TCP協(xié)議,要求建立和釋放連接,適用于可靠的交互過程; 也可以是無連接的U

3、DP協(xié)議,適用于可靠性要求不高的或?qū)崟r的交互過程; 同時使用TCP和UDP的服務(wù),有兩種服務(wù)器軟件的實(shí)現(xiàn)或服務(wù)器軟件同時和TCP、UDP協(xié)議交互,不對客戶做限制。面向連接的套接字的系統(tǒng)調(diào)用時序圖無連接協(xié)議的套接字調(diào)用時序圖 18.1.2 并發(fā)和迭代 能同時接受多個客戶連接的服務(wù)器稱為并發(fā)并發(fā)服務(wù)器服務(wù)器(concurrent server)一次只能接受一個客戶連接的服務(wù)器稱為迭迭代服務(wù)器代服務(wù)器(iterative server)由于服務(wù)器軟件要支持多個客戶的同時訪問,它必須具備并發(fā)性。服務(wù)器軟件為每個新到的客戶創(chuàng)建一個進(jìn)程或線程來處理和這個客戶的通信。服務(wù)器方傳送層實(shí)體使用客戶的源端口號和服

4、務(wù)的端口號來確定正確的服務(wù)器軟件進(jìn)程(線程)。 18.2 Winsock I/O模型 常用的Winsock I/O模型有5種:I/O復(fù)用select消息機(jī)制WSAAsyncSelect事件機(jī)制-WSAEventSelect重疊I/0模型I/O完成端口IOCP18.2.1 I/O復(fù)用select簡述簡述:確定一個或多個套接口的狀態(tài),如需要則等待。#include int selectselect( int nfds, fd_set FAR* readfds,fd_set FAR* writefds, fd_set FAR* exceptfds,const struct timeval FAR*

5、timeout);nfds:本參數(shù)忽略,僅起到兼容作用。readfds:(可選)指針,指向一組等待可讀性檢查的套接口。writefds:(可選)指針,指向一組等待可寫性檢查的套接口。exceptfds:(可選)指針,指向一組等待錯誤檢查的套接口。timeout:select()最多等待時間,對阻塞操作則為NULL。18.2.1 I/O復(fù)用select注釋注釋: 本函數(shù)用于確定一個或多個套接口的狀態(tài)。對每一個套接口,調(diào)用者可查詢它的可讀性、可寫性及錯誤狀態(tài)信息。用fd_set結(jié)構(gòu)來表示一組等待檢查的套接口。在調(diào)用返回時,這個結(jié)構(gòu)存有滿足一定條件的套接口組的子集,并且select()返回滿足條件的

6、套接口的數(shù)目。有一組宏可用于對fd_set的操作,這些宏與Berkeley Unix軟件中的兼容,但內(nèi)部的表達(dá)是完全不同的。 18.2.1 I/O復(fù)用selectreadfds參數(shù)標(biāo)識等待可讀性檢查的套接口。如果該套接口正處于監(jiān)聽listen()狀態(tài),則若有連接請求到達(dá),該套接口便被標(biāo)識為可讀,這樣一個accept()調(diào)用保證可以無阻塞完成。對其他套接口而言,可讀性意味著有排隊(duì)數(shù)據(jù)供讀取。或者對于SOCK_STREAM類型套接口來說,相對于該套接口的虛套接口已關(guān)閉,于是recv()或recvfrom()操作均能無阻塞完成。如果虛電路被“優(yōu)雅地”中止,則recv()不讀取數(shù)據(jù)立即返回;如果虛電路

7、被強(qiáng)制復(fù)位,則recv()將以WSAECONNRESET錯誤立即返回。如果SO_OOBINLINE選項(xiàng)被設(shè)置,則將檢查帶外數(shù)據(jù)是否存在。 18.2.1 I/O復(fù)用selectwritefds參數(shù)標(biāo)識等待可寫性檢查的套接口。如果一個套接口正在connect()連接(非阻塞),可寫性意味著連接順利建立。如果套接口并未處于connect()調(diào)用中,可寫性意味著send()和sendto()調(diào)用將無阻塞完成。但并未指出這個保證在多長時間內(nèi)有效,特別是在多線程環(huán)境中。 18.2.1 I/O復(fù)用selectexceptfds參數(shù)標(biāo)識等待帶外數(shù)據(jù)存在性或意味錯誤條件檢查的套接口。請注意如果設(shè)置了SO_OOB

8、INLINE選項(xiàng)為假FALSE,則只能用這種方法來檢查帶外數(shù)據(jù)的存在與否。對于SO_STREAM類型套接口,遠(yuǎn)端造成的連接中止和KEEPALIVE錯誤都將被作為意味出錯。如果套接口正在進(jìn)行連接connect()(非阻塞方式),則連接試圖的失敗將會表現(xiàn)在exceptfds參數(shù)中。18.2.1 I/O復(fù)用select如果對readfds、writefds或exceptfds中任一個組類不感興趣,可將它置為空NULL。18.2.1 I/O復(fù)用select在winsock.h頭文件中共定義了四個宏來操作描述字集。FD_SETSIZE變量用于確定一個集合中最多有多少描述字(FD_SETSIZE缺省值為6

9、4,可在包含winsock.h前用#define FD_SETSIZE來改變該值)。對于內(nèi)部表示,fd_set被表示成一個套接口的隊(duì)列,最后一個有效元素的后續(xù)元素為INVAL_SOCKET。宏為: FD_CLR(s,*set):從集合set中刪除描述字s。 FD_ISSET(s,*set):若s為集合中一員,非零;否則為零。 FD_SET(s,*set):向集合添加描述字s。 FD_ZERO(*set):將set初始化為空集NULL。18.2.1 I/O復(fù)用selecttimeout參數(shù)控制select()完成的時間。若timeout參數(shù)為空指針,則select()將一直阻塞到有一個描述字滿足

10、條件。否則的話,timeout指向一個timeval結(jié)構(gòu),其中指定了select()調(diào)用在返回前等待多長時間。如果timeval為0,0,則select()立即返回,這可用于探詢所選套接口的狀態(tài)。如果處于這種狀態(tài),則select()調(diào)用可認(rèn)為是非阻塞的,且一切適用于非阻塞調(diào)用的假設(shè)都適用于它。舉例來說,阻塞鉤子函數(shù)不應(yīng)被調(diào)用,且WINDOWS套接口實(shí)現(xiàn)不應(yīng)yield。18.2.1 I/O復(fù)用select返回值返回值: select()調(diào)用返回處于就緒狀態(tài)并且已經(jīng)包含在fd_set結(jié)構(gòu)中的描述字總數(shù); 如果超時則返回0; 否則的話,返回SOCKET_ERROR錯誤,應(yīng)用程序可通過WSAGetLa

11、stError()獲取相應(yīng)錯誤代碼。18.2.1 I/O復(fù)用select 錯誤代碼錯誤代碼: WSANOTINITIALISED:在使用此API之前應(yīng)首先成功地調(diào)用WSAStartup()。 WSAENETDOWN:WINDOWS套接口實(shí)現(xiàn)檢測到網(wǎng)絡(luò)子系統(tǒng)失效。 WSAEINVAL:超時時間值非法。 WSAEINTR:通過一個WSACancelBlockingCall()來取消一個(阻塞的)調(diào)用。 WSAEINPROGRESS:一個阻塞的WINDOWS套接口調(diào)用正在運(yùn)行中。 WSAENOTSOCK:描述字集合中包含有非套接口的元素。18.2.2 消息機(jī)制-WSAAsyncSelect 簡述簡述

12、:通知套接口有請求事件發(fā)生.#include int WSAAsyncSelect ( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );s:標(biāo)識一個需要事件通知的套接口的描述符.hWnd:標(biāo)識一個在網(wǎng)絡(luò)事件發(fā)生時需要接收消息的窗口句柄.wMsg:在網(wǎng)絡(luò)事件發(fā)生時要接收的消息.lEvent:位屏蔽碼,用于指明應(yīng)用程序感興趣的網(wǎng)絡(luò)事件集合.18.2.2 消息機(jī)制-WSAAsyncSelect注釋注釋:本函數(shù)用來請求Windows Sockets DLL為窗口句柄發(fā)一條消息無論它何時檢測到由lEvent參數(shù)指明的網(wǎng)絡(luò)事件.要發(fā)送的消息由wM

13、sg參數(shù)標(biāo)明.被通知的套接口由s標(biāo)識. 本函數(shù)自動將套接口設(shè)置為非阻塞模式.18.2.2 消息機(jī)制-WSAAsyncSelect事件值含義FD_READ期望在套接字上收到數(shù)據(jù)(即讀準(zhǔn)備好)時接到通知FD_WRITE期望在套接字上可發(fā)送數(shù)據(jù)(即寫準(zhǔn)備好)時接到通知FD_OOB 期望在套接字上有帶外數(shù)據(jù)到達(dá)時接到通知FD_ACCEPT 期望在套接字上有外來連接時接到通知FD_CONNECT 期望在套接字連接建立完成時接到通知FD_CLOSE 期望在套接字關(guān)閉時接到通知lEvent參數(shù)由下表中列出的值組成:18.2.2 消息機(jī)制-WSAAsyncSelect返回值返回值: 0:若應(yīng)用程序感興趣的網(wǎng)絡(luò)

14、事件的聲明成功. SOCKET_ERROR:可通過調(diào)用WSAGetLastError()返回特定的錯誤代碼.18.2.2 消息機(jī)制-WSAAsyncSelect事件值含義FD_READ套接口s準(zhǔn)備讀FD_WRITE套接口s準(zhǔn)備寫FD_OOB 帶外數(shù)據(jù)準(zhǔn)備好在套接口s上讀FD_ACCEPT 套接口s準(zhǔn)備接收新的將要到來的連接FD_CONNECT 套接口s上的連接完成FD_CLOSE 由套接口s標(biāo)識的連接已關(guān)閉返回的可能網(wǎng)絡(luò)事件如下 :網(wǎng)絡(luò)事件與重新激活函數(shù)網(wǎng)絡(luò)事件 重新激活函數(shù)FD_READrecv() 或 recvfrom()FD_WRITEsend() 或 sendto()FD_OOBrec

15、v()FD_ACCEPTaccept() 或WSAAccept(),直到返回的錯誤代碼為 WSATRY_AGAIN,指明條件函數(shù)返回CF_DEFER。FD_CONNECTNONEFD_CLOSENONEFD_QOS用SIO_GET_QOS 命令調(diào)用WSAIoctl()FD_GROUP_QOS用SIO_GET_GROUP_QOS命令調(diào)用WSAIoctl()18.2.3 事件機(jī)制-WSAEventSelect簡述簡述:確定與所提供的FD_XXX網(wǎng)絡(luò)事件集合相關(guān)的一個事件對象。 #include int WSAAPI WSAEventSelect ( SOCKET s, WSAEVENT hEven

16、tObject, long lNetworkEvents ); s:一個標(biāo)識套接口的描述字。hEventObject:一個句柄,用于標(biāo)識與所提供的FD_XXX網(wǎng)絡(luò)事件集合相關(guān)的一個事件對象。lNetworkEvents:一個屏蔽位,用于指定感興趣的FD_XXX網(wǎng)絡(luò)事件組合。18.2.3 事件機(jī)制-WSAEventSelect返回值返回值: 如果應(yīng)用程序指定的網(wǎng)絡(luò)事件及其相應(yīng)的事件對象成功設(shè)置,則返回0。否則的話,將返回INVALID_SOCKET錯誤,應(yīng)用程序可通過WSAGetLastError()來獲取相應(yīng)的錯誤代碼。 18.2.3 事件機(jī)制-WSAEventSelect 錯誤代碼:錯誤代碼

17、:WSANOTINITIALISED:在調(diào)用本API之前應(yīng)成功調(diào)用WSAStartup()。WSAENETDOWN: 網(wǎng)絡(luò)子系統(tǒng)失效。WSAEINVAL:參數(shù)中有非法值,或者指定的套接口處于非法狀態(tài)。WSAEINPROGRESS:一個阻塞的WinSock調(diào)用正在進(jìn)行中,或者服務(wù)提供者仍在處理一個回調(diào)函數(shù)WSAENOTSOCK:描述字不是一個套接口。18.2.3 事件機(jī)制-WSAEventSelectWSAEnumNetworkEvents()WSAEnumNetworkEvents()函數(shù):函數(shù):簡述簡述:檢測所指定套接口上網(wǎng)絡(luò)事件的發(fā)生。 #include int WSAAPI WSAEnu

18、mNetworkEvents ( SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents, LPINT lpiCount);s:標(biāo)識套接口的描述字。hEventObject:(可選)句柄,用于標(biāo)識需要復(fù)位的相應(yīng)事件對象。lpNetworkEvents:一個WSANETWORKEVENTS結(jié)構(gòu)的數(shù)組,每一個元素記錄了一個網(wǎng)絡(luò)事件和相應(yīng)的錯誤代碼。lpiCount:數(shù)組中的元素?cái)?shù)目。在返回時,本參數(shù)表示數(shù)組中的實(shí)際元素?cái)?shù)目;如果返回值是WSAENOBUFS,則表示為獲取所有網(wǎng)絡(luò)事件所需的元素?cái)?shù)目。18.2.3 事件機(jī)制

19、-WSAEventSelect返回值返回值: 如果操作成功則返回0。否則的話,將返回INVALID_SOCKET錯誤,應(yīng)用程序可通過WSAGetLastError()來獲取相應(yīng)的錯誤代碼。錯誤代碼錯誤代碼:WSANOTINITIALISED:在調(diào)用本API之前應(yīng)成功調(diào)用WSAStartup()。WSAENETDOWN:網(wǎng)絡(luò)子系統(tǒng)失效。WSAEINVAL:參數(shù)中有非法值。WSAEINPROGRESS: 一個阻塞的WinSock調(diào)用正在進(jìn)行中,或者服務(wù)提供者仍在處理一個回調(diào)函數(shù)WSAENOBUFS所提供的緩沖區(qū)太小。18.2.3 事件機(jī)制-WSAEventSelectWSAWaitForMulti

20、pleEventsWSAWaitForMultipleEvents函數(shù):簡述簡述:用于等待某個事件的觸發(fā)。DWORD WSAWaitForMultipleEvents( DWORD cEvents, / 等候事件的總數(shù)量 const WSAEVENT* lphEvents, / 事件數(shù)組的指針 BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable ) 18.2.3 事件機(jī)制-WSAEventSelectfWaitAll:如果設(shè)置為 TRUE,則事件數(shù)組中所有事件被傳信的時候函數(shù)才會返回,F(xiàn)ALSE則任何一個事件被傳信函數(shù)都要返回,一般設(shè)置為FALSE。

21、 dwTimeout:超時時間,如果超時,函數(shù)會返回 WSA_WAIT_TIMEOUT, 如果設(shè)置為0,函數(shù)會立即返回返回值:返回值: WSA_WAIT_TIMEOUT :最常見的返回值,我們需要做的就是繼續(xù)等待。 WSA_WAIT_FAILED : 出現(xiàn)了錯誤,請檢查cEvents和lphEvents兩個參數(shù)是否有效如果事件數(shù)組中有某一個事件被傳信了,函數(shù)會返回這個事件的索引值,但是這個索引值需要減去預(yù)定義值 WSA_WAIT_EVENT_0才是這個事件在事件數(shù)組中的位置。 18.2.4 重疊I/0模型 首先,肯定是需要一個SOCKET數(shù)組 ,分別用來和每一個SOCKET通信其次,因?yàn)橹丿B模

22、型中每一個SOCKET操作都是要“綁定”一個重疊結(jié)構(gòu)的,所以需要為每一個SOCKET操作搭配一個WSAOVERLAPPED結(jié)構(gòu),但是這樣說并不嚴(yán)格,因?yàn)槿绻恳粋€SOCKET同時只有一個操作,比如WSARecv,那么一個SOCKET就可以對應(yīng)一個WSAOVERLAPPED結(jié)構(gòu),但是如果一個SOCKET上會有WSARecv 和WSASend兩個操作,那么一個SOCKET肯定就要對應(yīng)兩個WSAOVERLAPPED結(jié)構(gòu),所以有多少個SOCKET操作就會有多少個WSAOVERLAPPED結(jié)構(gòu)。18.2.4 重疊I/0模型然后,同樣是為每一個WSAOVERLAPPED結(jié)構(gòu)都要搭配一個WSAEVENT事件

23、,所以說有多少個SOCKET操作就應(yīng)該有多少個WSAOVERLAPPED結(jié)構(gòu),有多少個WSAOVERLAPPED結(jié)構(gòu)就應(yīng)該有多少個WSAEVENT事件,最好把SOCKET WSAOVERLAPPED WSAEVENT三者的關(guān)聯(lián)起來。18.2.4 重疊I/0模型不得不分作兩個線程:一個用來循環(huán)監(jiān)聽端口,接收請求的連接,然后給在這個套接字上配合一個WSAOVERLAPPED結(jié)構(gòu)投遞第一個WSARecv請求,然后進(jìn)入第二個線程中等待操作完成。第二個線程用來不停的對WSAEVENT數(shù)組WSAWaitForMultipleEvents,等待任何一個重疊操作的完成,然后根據(jù)返回的索引值進(jìn)行處理,處理完畢以

24、后再繼續(xù)投遞另一個WSARecv請求。這里需要注意一點(diǎn)的是,前面我是把WSAWaitForMultipleEvents函數(shù)的參數(shù)設(shè)置為WSA_INFINITE的,但是在多客戶端的時候這樣就不OK了,需要設(shè)定一個超時時間,如果等待超時了再重新WSAWaitForMultipleEvents,因?yàn)閃SAWaitForMultipleEvents函數(shù)在沒有觸發(fā)的時候是阻塞在那里的,我們可以設(shè)想一下,這時如果監(jiān)聽線程忠接入了新的連接,自然也會為這個連接增加一個Event,但是WSAWaitForMultipleEvents還是阻塞在那里就不會處理這個新連接的Event了。WSABUF結(jié)構(gòu)typedef

25、 struct _WSABUF u_long len; /* the length of the buffer */ char FAR * buf; /* the pointer to the buffer */ WSABUF, FAR * LPWSABUF;WSAOVERLAPPED結(jié)構(gòu)typedef struct _WSAOVERLAPPED DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; WSAEVENT hEvent; WSAOVERLAPPED, FAR * LPWSAOVERLAPPED;LPW

26、SAOVERLAPPED_COMPLETION_ROUTINETypedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE) ( DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags );WSASocket()簡述:創(chuàng)建一個與指定傳送服務(wù)提供者捆綁的套接口,可選地創(chuàng)建和/或加入一個套接口組。#include SOCKET WSAAPI WSASocket ( int af, int type, int protocol, LPPRO

27、TOCOL_INFO lpProtocolInfo, Group g, int iFlags);WSASocket()af:地址族描述。type:新套接口的類型描述。protocol:套接口使用的特定協(xié)議,如果調(diào)用者不愿指定協(xié)議則定為0。lpProtocolInfo:一個指向PROTOCOL_INFO結(jié)構(gòu)的指針,該結(jié)構(gòu)定義所創(chuàng)建套接口的特性。如果本參數(shù)非零,則前三個參數(shù)(af, type, protocol)被忽略。g:套接口組的描述字。iFlags:套接口屬性描述。WSASocket()返回值:若無錯誤發(fā)生,WSASocket()返回新套接口的描述字。否則的話,返回 INVALID_SOCK

28、ET,應(yīng)用程序可定調(diào)用WSAGetLastError()來獲取相應(yīng)的錯誤代碼。錯誤代碼 含義WSANOTINITIALISED 在調(diào)用本API之前應(yīng)成功調(diào)用WSAStartup()。 WSAENETDOWN 網(wǎng)絡(luò)子系統(tǒng)失效 WSAEAFNOSUPPORT 不支持指定的地址族 WSAEINPROGRESS 一個阻塞的WinSock調(diào)用正在進(jìn)行中,或者服務(wù)提供者仍在處理一個回調(diào)函數(shù) WSAEMFILE 無可用的套接口描述字 WSAENOBUFS 無可用的緩沖區(qū)空間。套接口無法創(chuàng)建。WSAEPROTONOSUPPORT 不支持指定的協(xié)議 WSAEPROTOTYPE 指定的協(xié)議對于本套接口類型錯誤 W

29、SAESOCKTNOSUPPORT 本地址族不支持指定的套接口類型 WSAEINVAL g參數(shù)非法 18.2.4 重疊I/0模型四個WINSOCK2中的重疊I/0操作函數(shù):lWSARecv()lWSASend()lWSARecvFrom()lWSASendTo()WSARecv()Int WSAAPI WSARecv( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLA

30、PPED_COMPLETION_ROUTINE lpCompletionRoutine );WSARecv()s:一個標(biāo)識已連接套接口的描述字。lpBuffers:一個指向WSABUF結(jié)構(gòu)數(shù)組的指針。每一個WSABUF結(jié)構(gòu)包含一個緩沖區(qū)的指針和緩沖區(qū)的長度。dwBufferCount:lpBuffers數(shù)組中WSABUF結(jié)構(gòu)的數(shù)目。lpNumberOfBytesRecvd:如果接收操作立即結(jié)束,一個指向本調(diào)用所接收的字節(jié)數(shù)的指針。lpFlags:一個指向標(biāo)志位的指針。lpOverlapped:一個指向WSAOVERLAPPED結(jié)構(gòu)的指針(對于非重疊套接口則忽略)。lpCompletionRou

31、tine:一個指向接收操作結(jié)束后調(diào)用的例程的指針(對于非重疊套接口則忽略)。WSARecv()返回值: 若無錯誤發(fā)生且接收操作立即完成,則WSARecv()函數(shù)返回所接收的字節(jié)數(shù)。如果連接結(jié)束,則返回0。請注意在這種情況下完成指示(啟動指定的完成例程或設(shè)置一個事件對象)將早已發(fā)生。否則的話,將返回SOCKET_ERROR錯誤,應(yīng)用程序可通過WSAGetLastError()來獲取相應(yīng)的錯誤代碼。錯誤代碼WSA_IO_PENDING表示重疊操作成功啟動,過后將有完成指示。任何其他的錯誤表示重疊操作未能成功地啟動,以后也不會有完成指示。 如果設(shè)置了MSG_INTERRUPT標(biāo)志,則返回值的含義變化

32、。零表示成功,具體含義同上。否則的話,返回值直接包含如下所示的錯誤代碼。由于中斷環(huán)境中無法調(diào)用WSAGetLastError(),故是必需的。請注意僅適用于Win16環(huán)境,僅適用于PROTOCOL_INFO結(jié)構(gòu)中設(shè)置了XP1_INTERRUPT位的協(xié)議。WSASend()Int WSAAPI WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COM

33、PLETION_ROUTINE lpCompletionRoutine );WSASend()s:標(biāo)識一個已連接套接口的描述字。lpBuffers:一個指向WSABUF結(jié)構(gòu)數(shù)組的指針。每個WSABUF結(jié)構(gòu)包含緩沖區(qū)的指針和緩沖區(qū)的大小。dwBufferCount:lpBuffers數(shù)組中WSABUF結(jié)構(gòu)的數(shù)目。lpNumberOfBytesSent:如果發(fā)送操作立即完成,則為一個指向所發(fā)送數(shù)據(jù)字節(jié)數(shù)的指針。iFlags:標(biāo)志位。lpOverlapped:指向WSAOVERLAPPED結(jié)構(gòu)的指針(對于非重疊套接口則忽略)。lpCompletionRoutine:一個指向發(fā)送操作完成后調(diào)用的完成例

34、程的指針。(對于非重疊套接口則忽略)。WSASend()返回值: 若無錯誤發(fā)生且發(fā)送操作立即完成,則WSASend()函數(shù)返回所發(fā)送的字節(jié)數(shù)。(注意該數(shù)目可能小于len參數(shù)所指定的值)。如果連接結(jié)束,則返回0。請注意在這種情況下完成指示(啟動指定的完成例程或設(shè)置一個事件對象)將早已發(fā)生。否則的話,將返回SOCKET_ERROR錯誤,應(yīng)用程序可通過WSAGetLastError()來獲取相應(yīng)的錯誤代碼。錯誤代碼WSA_IO_PENDING表示重疊操作成功啟動,過后將有完成指示。任何其他的錯誤表示重疊操作未能成功地啟動,以后也不會有完成指示。 如果設(shè)置了MSG_INTERRUPT標(biāo)志,則返回值的含

35、義變化。零表示成功,具體含義同上。否則的話,返回值直接包含如下所示的錯誤代碼。由于中斷環(huán)境中無法調(diào)用WSAGetLastError(),故是必需的。請注意僅適用于Win16環(huán)境,僅適用于PROTOCOL_INFO結(jié)構(gòu)中設(shè)置了XP1_INTERRUPT位的協(xié)議。WSARecvFrom()Int WSAAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR * lpFrom, LPINT

36、 lpFromlen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );WSARecvFrom()s:一個標(biāo)識套接口的描述字。lpBuffers:一個指向WSABUF結(jié)構(gòu)數(shù)組的指針。每個WSABUF結(jié)構(gòu)包含緩沖區(qū)的指針和緩沖區(qū)的大小。dwBufferCount:lpBuffers數(shù)組中WSABUF結(jié)構(gòu)的數(shù)目。lpNumberOfBytesRecvd:如果接收操作立即完成,則為一個指向所接收數(shù)據(jù)字節(jié)數(shù)的指針。lpFlags:一個指向標(biāo)志位的指針。lpFrom:可選指針,指

37、向重疊操作完成后存放源地址的緩沖區(qū)。lpFromlen:指向from緩沖區(qū)大小的指針,僅當(dāng)指定了lpFrom才需要。lpOverlapped:指向WSAOVERLAPPED結(jié)構(gòu)的指針(對于非重疊套接口則忽略)。lpCompletionRoutine:一個指向接收操作完成后調(diào)用的完成例程的指針。(對于非重疊套接口則忽略)。WSARecvFrom()返回值: 若無錯誤發(fā)生且接收操作立即完成,則WSARecvFrom()函數(shù)返回所接收的字節(jié)數(shù)。如果連接結(jié)束,則返回0。請注意在這種情況下完成指示(啟動指定的完成例程或設(shè)置一個事件對象)將早已發(fā)生。否則的話,將返回SOCKET_ERROR錯誤,應(yīng)用程序可

38、通過WSAGetLastError()來獲取相應(yīng)的錯誤代碼。錯誤代碼WSA_IO_PENDING表示重疊操作成功啟動,過后將有完成指示。任何其他的錯誤表示重疊操作未能成功地啟動,以后也不會有完成指示。 如果設(shè)置了MSG_INTERRUPT標(biāo)志,則返回值的含義變化。零表示成功,具體含義同上。否則的話,返回值直接包含如下所示的錯誤代碼。由于中斷環(huán)境中無法調(diào)用WSAGetLastError(),故是必需的。請注意僅適用于Win16環(huán)境,僅適用于PROTOCOL_INFO結(jié)構(gòu)中設(shè)置了XP1_INTERRUPT位的協(xié)議。WSASendTo()Int WSAAPI WSASendTo( SOCKET s,

39、 LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, const struct sockaddr FAR * lpTo, int iTolen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );WSASendTo()s:用于標(biāo)識一個已連接的套接口,該套接口以WSA_FLAG_OVERLAPPED標(biāo)志調(diào)用WSASocket()創(chuàng)建。lpBuffers:一個

40、指向WSABUF結(jié)構(gòu)數(shù)組的指針。每個WSABUF結(jié)構(gòu)包含緩沖區(qū)的指針和緩沖區(qū)的大小。dwBufferCount:lpBuffers數(shù)組中WSABUF結(jié)構(gòu)的數(shù)目。lpNumberOfBytesSent:如果發(fā)送操作立即完成,則為一個指向所發(fā)送數(shù)據(jù)字節(jié)數(shù)的指針。iFlags:標(biāo)志位。lpTo:(可選)指針,指向目標(biāo)套接口的地址。lpTolen:lpTo中地址的大小。lpOverlapped:指向WSAOVERLAPPED結(jié)構(gòu)的指針(對于非重疊套接口則忽略)。lpCompletionRoutine:一個指向發(fā)送操作完成后調(diào)用的完成例程的指針。(對于非重疊套接口則忽略)。WSASendTo()返回值:

41、 若無錯誤發(fā)生且發(fā)送操作立即完成,則WSASendTo()函數(shù)返回所發(fā)送的字節(jié)數(shù)(請注意它可能小于len所指定的值)。請注意在這種情況下完成指示(啟動指定的完成例程或設(shè)置一個事件對象)將早已發(fā)生。否則的話,將返回SOCKET_ERROR錯誤,應(yīng)用程序可通過WSAGetLastError()來獲取相應(yīng)的錯誤代碼。錯誤代碼WSA_IO_PENDING表示重疊操作成功啟動,過后將有完成指示。任何其他的錯誤表示重疊操作未能成功地啟動,以后也不會有完成指示。 如果設(shè)置了MSG_INTERRUPT標(biāo)志,則返回值的含義變化。零表示成功,具體含義同上。否則的話,返回值直接包含如下所示的錯誤代碼。由于中斷環(huán)境中

42、無法調(diào)用WSAGetLastError(),故是必需的。請注意僅適用于Win16環(huán)境,僅適用于PROTOCOL_INFO結(jié)構(gòu)中設(shè)置了XP1_INTERRUPT位的協(xié)議。18.2.4 重疊I/0模型WSAGetOverlappedResultWSAGetOverlappedResult函數(shù)函數(shù):簡述簡述:返回指定套接口上一個重疊操作的結(jié)果。BOOL WSAAPI WSAGetOverlappedResult( SOCKET s, LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer, BOOL fWait, LPDWORD lpdwFlags );

43、WSAGetOverlappedResultWSAGetOverlappedResults:標(biāo)識套接口。這就是調(diào)用重疊操作(WSARecv()、 WSARecvFrom()、WSASend()、WSASendTo() 或 WSAIoctl())時指定的那個套接口。lpOverlapped:指向調(diào)用重疊操作時指定的WSAOVERLAPPED結(jié)構(gòu)。lpcbTransfer:指向一個32位變量,該變量用于存放一個發(fā)送或接收操作實(shí)際傳送的字節(jié)數(shù),或WSAIoctl()傳送的字節(jié)數(shù)。fWait:指定函數(shù)是否等待掛起的重疊操作結(jié)束。若為真TRUE則函數(shù)在操作完成后才返回。若為假FALSE且函數(shù)掛起,則函數(shù)

44、返回FALSE,WSAGetLastError()函數(shù)返回WSA_IO_INCOMPLETE。lpdwFlags:指向一個32位變量,該變量存放完成狀態(tài)的附加標(biāo)志位。如果重疊操作為WSARecv()或WSARecvFrom(),則本參數(shù)包含lpFlags參數(shù)所需的結(jié)果。WSAGetOverlappedResultWSAGetOverlappedResult返回值返回值: 如果函數(shù)成功,則返回值為真TRUE。它意味著重疊操作已經(jīng)完成,lpcbTransfer所指向的值已經(jīng)被刷新。應(yīng)用程序可調(diào)用WSAGetLastError()來獲取重疊操作的錯誤信息。 如果函數(shù)失敗,則返回值為假FALSE。它意

45、味著要么重疊操作未完成,要么由于一個或多個參數(shù)的錯誤導(dǎo)致無法決定完成狀態(tài)。失敗時,lpcbTransfer指向的值不會被刷新。應(yīng)用程序可用WSAGetLastError()來獲取失敗的原因。WSAGetOverlappedResultWSAGetOverlappedResult錯誤代碼錯誤代碼:WSANOTINITIALISED:在調(diào)用本API之前應(yīng)成功調(diào)用WSAStartup()。WSAENETDOWN:網(wǎng)絡(luò)子系統(tǒng)失效。WSAENOTSOCK :描述字不是一個套接口。WSA_INVALID_HANDLE:WSAOVERLAPPED結(jié)構(gòu)的hEvent域未包含一個有效的事件對象句柄。WSA_IN

46、VALID_PARAMETER:有不可接受的參數(shù)。WSA_IO_INCOMPLETE:fWait假FALSE且輸入/輸出操作尚未完成。18.2.5 I/O完成端口IOCP “完成端口”模型是迄今為止最為復(fù)雜的一種I/O模型。IOCP全稱I/O Completion Port,中文譯為I/O完成端口。IOCP是一個異步I/O的API,它可以高效地將I/O事件通知給應(yīng)用程序。該模型只適用于以下操作系統(tǒng)(微軟的):Windows NT和Windows 2000之后的操作系統(tǒng)。 18.2.5 I/O完成端口IOCP因其設(shè)計(jì)的復(fù)雜性,只有在你的應(yīng)用程序需要同時管理數(shù)百乃至上千個套接字的時候、而且希望隨著

47、系統(tǒng)內(nèi)安裝的CPU數(shù)量的增多、應(yīng)用程序的性能也可以線性提升,才應(yīng)考慮采用“完成端口”模型。要記住的一個基本準(zhǔn)則是,假如要為Windows NT或windows 2000開發(fā)高性能的服務(wù)器應(yīng)用,同時希望為大量套接字I/O請求提供服務(wù)(Web服務(wù)器便是這方面的典型例子),那么I/O完成端口模型便是最佳選擇. 什么是線程什么是線程 線程是指程序的一個指令執(zhí)行序列,WIN32 平臺支持多線程程序,允許程序中存在多個線程。 在單 CPU 系統(tǒng)中,系統(tǒng)把 CPU 的時間片按照調(diào)度算法分配給各個線程,因此各線程實(shí)際上是分時執(zhí)行的,在多 CPU 的 Windows NT 系統(tǒng)中, 同一個程序的不同線程可以被分

48、配到不同的 CPU 上去執(zhí)行。由于一個程序的各線程是在相同的地址空間運(yùn)行的,因此設(shè)及到了如何共享內(nèi)存, 如何進(jìn)行線程通信等問題18.2.5.1基本函數(shù)IOCP涉及到的三個基本函數(shù):lCreateIoCompletionPort lGetQueuedCompletionStatus lPostQueuedCompletionStatus CreateIoCompletionPortHANDLE CreateIoCompletionPort( HANDLE FileHandle, HANDLE ExistingCompletionPort, DWORD CompletionKey, DWORD N

49、umberOfConcurrentThreads ); 該函數(shù)實(shí)際用于兩個明顯有別的目的: l用于創(chuàng)建個完成端口對象。 l將一個套接口同完成端口關(guān)聯(lián)到一起。 CreateIoCompletionPort最開始創(chuàng)建個完成端口的時候,唯一感興趣的參數(shù)便是NumberOfConcurrentThreads(并發(fā)線程的數(shù)量);前面三個參數(shù)都會被忽略。NumberOfConcurrentThreads 參數(shù)的特殊之處在于:它定義了在一個完成端口上,同時允許執(zhí)行的線程數(shù)量。理想情況下我們希望每個處理器各自負(fù)責(zé)個線程的運(yùn)行,為完成端口提供服務(wù),避免過于頻繁的線程“場景”切換。若將該參數(shù)設(shè)為若將該參數(shù)設(shè)為0,

50、0,說明系統(tǒng)內(nèi)說明系統(tǒng)內(nèi)安裝了多少個處理器安裝了多少個處理器, ,便允許同時運(yùn)行多少個線程!便允許同時運(yùn)行多少個線程!可用下述代碼創(chuàng)建一個I/O完成端口: CompetionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0) CreateIoCompletionPortCreateIoCompletionPort函數(shù)的NumberofConcurrentThreads參數(shù)明確指示系統(tǒng):在一個完成端口上,一次只允許n個工作者線程運(yùn)行。假如在完成端門上創(chuàng)建的工作者線程數(shù)量超出n個那么在同一時刻,最多只允許n個線程運(yùn)行。 但實(shí)際上,在

51、段較短的時間內(nèi),系統(tǒng)有可能超過這個值。但很快便會把它減少至事先在CreateIoCompletionPort函數(shù)中設(shè)定的值。CreateIoCompletionPort那么那么, ,為何實(shí)際創(chuàng)建的工作者線程數(shù)最有時要比為何實(shí)際創(chuàng)建的工作者線程數(shù)最有時要比CreateIoCompletionPortCreateIoCompletionPort函數(shù)設(shè)定的多函數(shù)設(shè)定的多些呢些呢? ?這樣做有必這樣做有必要嗎要嗎? ?如先前所述,這主要取決于應(yīng)用程序的總體設(shè)計(jì)情況,假設(shè)我們的工作者線程調(diào)用了一個函數(shù),比如Sleep()或者WaitForSingleobject(),但卻進(jìn)入了暫停(鎖定或掛起)狀態(tài)、那

52、么允許另個線程代替它的位置。換言之,我們希望隨時都能執(zhí)行盡可能多的線程;當(dāng)然,最大的線程數(shù)量是事先在CreateIoCompletonPort調(diào)用里設(shè)定好的。這樣來。假如事先預(yù)料到自己的線程有可能暫時處于停頓狀態(tài),那么最好能夠創(chuàng)建比CreateIoCompletionPort的NumberofConcurrentThreads參數(shù)的值多的線程以便到時候充分發(fā)揮系統(tǒng)的潛力。 CreateIoCompletionPort在默認(rèn)情況下,所開線程數(shù)和CPU數(shù)量相同,但經(jīng)驗(yàn)給我們一個公式:線程數(shù)線程數(shù) = CPU數(shù)數(shù) * 2 + 2CompletionKey(完成鍵)CompletionKey(完成鍵)

53、參數(shù)則指定要與某個特定套接字句柄關(guān)聯(lián)在起的“單句柄數(shù)據(jù)”,在這個參數(shù)中,應(yīng)用程序可保存與個套接字對應(yīng)的任意類型的信息。之所以把它叫作“單句柄數(shù)據(jù)”,是由于它只對應(yīng)著與那個套接字句柄關(guān)聯(lián)在起的數(shù)據(jù)??蓪⑵渥鳛橹赶蛞粋€數(shù)據(jù)結(jié)構(gòu)的指針、來保存套接字句柄;在那個結(jié)構(gòu)中,同時包含了套接字的句柄,以及與那個套接字有關(guān)的其他信息。就象本章稍后還會講述的那樣,為完成端口提供服務(wù)的線程例程可通過這個參數(shù)。取得與其套字句柄有關(guān)的信息。 GetQueuedCompletionStatusBOOL GetQueuedCompletionStatus( HANDLE CompletionPort, / handle t

54、o completion port LPDWORD lpNumberOfBytes, / bytes transferred PULONG_PTR lpCompletionKey, / file completion key LPOVERLAPPED *lpOverlapped, / buffer DWORD dwMilliseconds / optional timeout value);獲取排隊(duì)完成狀態(tài) GetQueuedCompletionStatusCompletionPort參數(shù)對應(yīng)與要在上面等待的完成端口. lpNumberOfBytesTransferred參數(shù)負(fù)責(zé)在完成了次I/

55、O操作后(如WSASend或WSARecv)、接收實(shí)際傳輸?shù)淖止?jié)數(shù)。 lpCompletionKey參數(shù)為原先傳遞進(jìn)入CreateCompletionPort函數(shù)的套接字返回“單句柄數(shù)據(jù)”。如我們早先所述,大家最好將套接字句柄保存在這個“鍵”(Key)中。 lpOverlapped參數(shù)用于接收完成的I/O操作的重疊結(jié)果。這實(shí)際是一個相當(dāng)重要的參數(shù),因?yàn)橐盟@取每個I/O操作的數(shù)據(jù)。 DwMilliseconds用于指定調(diào)用者希望等待一個完成數(shù)據(jù)包在完成端門上出現(xiàn)的時間。假如將其設(shè)為INFINITE。調(diào)用會無休止地等持下去。 PostQueuedCompletionStatus PostQueuedCompletionStatus函數(shù),向每個工作者線程都發(fā)送個特殊的完成數(shù)據(jù)包。該函數(shù)會指示每個線程都“立即結(jié)束并退出” BOOL PostQueuedCompletionStatus( HANDLE CompletlonPort, DW0RD dwNumberOfBytesTrlansferred, DWORD dwCompletlonKey, LPOVERLAPPED lpoverlapped, ); PostQueuedCompletionStatusCompletionPort參數(shù)指定想向其發(fā)送一個完成數(shù)據(jù)包的完成端口對象。而就dwNumberOfBytesTra

溫馨提示

  • 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論