網(wǎng)絡(luò)編程實用教程第7 8章-多線程編程課件_第1頁
網(wǎng)絡(luò)編程實用教程第7 8章-多線程編程課件_第2頁
網(wǎng)絡(luò)編程實用教程第7 8章-多線程編程課件_第3頁
網(wǎng)絡(luò)編程實用教程第7 8章-多線程編程課件_第4頁
網(wǎng)絡(luò)編程實用教程第7 8章-多線程編程課件_第5頁
已閱讀5頁,還剩119頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

網(wǎng)絡(luò)編程實用教程第7章WinSock的多線程編程2021/8/171網(wǎng)絡(luò)編程實用教程第7章WinSock的多線程編程2021本章內(nèi)容:WinSock需要多線程編程的原因:Win32操作系統(tǒng)下的多進程多線程機制、多線程機制在網(wǎng)絡(luò)編程中的應(yīng)用和VisualC++6.0對多線程網(wǎng)絡(luò)編程的支持。分析了MFC支持的兩種線程,給出了創(chuàng)建MFC的工作線程、創(chuàng)建并啟動用戶界面線程和終止線程的步驟。2021/8/172本章內(nèi)容:2021/8/1727.1WinSock為什么需要多線程編程2021/8/1737.1WinSock為什么需要多線程編程2021/8/17.1.1WinSock的兩種輸入輸出模式如前所述,WinSock在進行輸入輸出的時候,可以使用兩種工作模式:“阻塞”模式:又稱為同步模式“非阻塞”模式:又稱為異步模式

工作在“阻塞”模式下的套接字被稱為阻塞套接字,而工作在“非阻塞”模式下的套接字稱為非阻塞套接字。2021/8/1747.1.1WinSock的兩種輸入輸出模式如前所7.1.2兩種模式的優(yōu)缺點及解決方法“阻塞”與“非阻塞”模式的優(yōu)點和缺點:阻塞套接字的I/O操作工作情況比較確定,即調(diào)用、等待、返回。大部分情況下,I/O操作都能成功地完成,只是花費了等待的時間,容易編程;需要建立多個套接字連接來為多個客戶服務(wù)的時候,或在數(shù)據(jù)的收發(fā)量不均勻的時候,或在輸入輸出的時間不確定的時候,阻塞套接字的性能低下,甚至無能為力。2021/8/1757.1.2兩種模式的優(yōu)缺點及解決方法“阻塞”與“非阻塞”使用非阻塞套接字,需要編寫更多的代碼,因為必須恰當(dāng)?shù)匕盐照{(diào)用I/O函數(shù)的時機,盡量減少無功而返的調(diào)用,還必須詳加分析每個Winsock調(diào)用中收到的錯誤,采取相應(yīng)的對策,這種I/O操作的隨機性使得非阻塞套接字顯得難于操作。所以必須采取適當(dāng)?shù)膶Σ?,讓阻塞和非阻塞套接字能夠滿足各種場合的要求。對于非阻塞工作模式:引入了五種“套接字I/O模型”。阻塞的工作模式,則引入了多線程機制。2021/8/176使用非阻塞套接字,需要編寫更多的代碼,因為必須恰當(dāng)?shù)匕盐照{(diào)用7.2Win32操作系統(tǒng)下的多進程多線程機制2021/8/1777.2Win32操作系統(tǒng)下的多進程多線程機制2021/87.2.2Win32OS支持多線程應(yīng)用程序、進程及線程的關(guān)系DOS是單用戶單任務(wù)的。

Win32操作系統(tǒng)是多任務(wù)的,并且支持一個進程中有多個線程。一個線程(thread)是進程內(nèi)的一條執(zhí)行路徑,是一個應(yīng)用程序中的一條可執(zhí)行路徑。一個進程中至少要有一個線程,稱為主線程。當(dāng)啟動了一個應(yīng)用程序時,操作系統(tǒng)將為它創(chuàng)建了一個進程,同時創(chuàng)建該進程的主線程,并開始執(zhí)行主線程。主線程可以創(chuàng)建并啟動其他輔助線程,由主線程創(chuàng)建的線程又可以創(chuàng)建并啟動更多的線程。2021/8/1787.2.2Win32OS支持多線程應(yīng)用程序、進程及線程7.2.2Win32OS支持多線程單CPU分時地運行進程中的各個線程2021/8/1797.2.2Win32OS支持多線程單CPU分時地運行進7.2.3多線程機制在網(wǎng)絡(luò)編程中的應(yīng)用如果一個應(yīng)用程序,有多個任務(wù)需要同時進行處理,則適合使用多線程機制。對于網(wǎng)絡(luò)上客戶機軟件:采用多線程,能克服在單線程的編程模式下,由于阻塞等待而產(chǎn)生的客戶程序就不能及時響應(yīng)用戶的操作命令的問題。對于網(wǎng)絡(luò)上服務(wù)器軟件:采用多線程的編程技術(shù),能更好地為多個客戶服務(wù)。對于一個客戶:采用多線程機制也能大大提高應(yīng)用程序的運行效率。網(wǎng)絡(luò)在線實時監(jiān)控軟件:2021/8/17107.2.3多線程機制在網(wǎng)絡(luò)編程中的應(yīng)用如果一個應(yīng)7.3VC6.0對多線程網(wǎng)絡(luò)編程的支持VC6.0環(huán)境下,兩種開發(fā)程序的方法:直接使用Win32API來編寫Win32應(yīng)用程序利用MFC基礎(chǔ)類庫編寫C++風(fēng)格的應(yīng)用程序。在這兩種Windows應(yīng)用程序的開發(fā)方式下,多線程的編程原理是一致的。2021/8/17117.3VC6.0對多線程網(wǎng)絡(luò)編程的支持VC6.0環(huán)境下7.3.1MFC支持的兩種線程微軟的基礎(chǔ)類庫MFC提供了對于多線程應(yīng)用程序的支持。在MFC中,線程分為兩種:用戶接口線程:(user-interfacethread),或稱用戶界面線程;工作線程:(theworkerthread),這兩類線程可以滿足不同任務(wù)的處理需求。2021/8/17127.3.1MFC支持的兩種線程微軟的基礎(chǔ)類庫MF1、用戶接口線程

作用:用于處理用戶的輸入,響應(yīng)用戶產(chǎn)生的消息。MFC為用戶接口線程提供了一個消息泵。同時包含一個消息循環(huán),以應(yīng)對各種事件。

MFC應(yīng)用程序的CWinApp類對象是一個典型的用戶接口線程在MFC應(yīng)用程序中,CWinThread是用戶接口線程的基類,CWinApp就是從CWinThread類派生出來的,編寫用戶接口線程候,也需要從CWinThread類派生。2021/8/17131、用戶接口線程2021/8/17132.工作線程

工作線程(workerthread),適用于處理那些不要求用戶輸入并且比較消耗時間的其他任務(wù)。對用戶來說,工作線程運行在后臺。這就使得工作線程特別適合去等待一個事件的發(fā)生。CWinThread類同樣是工作線程的基類。在編寫工作線程的時候,可以調(diào)用MFC的AfxBeginThread函數(shù),來創(chuàng)建CWinThread對象。2021/8/17142.工作線程2021/8/17147.3.2創(chuàng)建MFC的工作線程利用MFC創(chuàng)建工作線程的步驟:第一步:編程實現(xiàn)控制函數(shù)第二步:創(chuàng)建并啟動工作線程一般不必從CWinThread派生一個類。如果需要一個特定版本的CWinThread類,也可以去派生;但對于大多數(shù)的工作線程是不要求的??梢圆蛔魅魏涡薷牡厥褂肅WinThread類。2021/8/17157.3.2創(chuàng)建MFC的工作線程利用MFC創(chuàng)建工作線程的步7.3.2創(chuàng)建MFC的工作線程1、編程實現(xiàn)控制函數(shù)一個工作線程對應(yīng)一個控制函數(shù)。線程執(zhí)行的任務(wù)都應(yīng)編寫在控制函數(shù)之中,規(guī)定了該線程的執(zhí)行代碼,當(dāng)控制函數(shù)執(zhí)行結(jié)束而退出時,線程也就隨之終止。編寫工作線程的控制函數(shù)必須遵守一定的格式,控制函數(shù)的原型聲明是:UINTControlFunctionName(LPVOIDpParam);

pParam是一個數(shù)據(jù)結(jié)構(gòu);2021/8/17167.3.2創(chuàng)建MFC的工作線程1、編程實現(xiàn)控制函數(shù)2027.3.2創(chuàng)建MFC的工作線程2.創(chuàng)建并啟動工作線程(Startingthethread)

啟動線程:即開始運行它對應(yīng)的控制函數(shù)。在主線程或其他線程中調(diào)用AfxBeginThread()函數(shù)就可以創(chuàng)建新的線程,并使新線程開始運行。一般將線程的創(chuàng)建者稱為新線程的父線程。AfxBeginThread()函數(shù)有兩個重載的版本,區(qū)別在于使用的入口參數(shù)不同。2021/8/17177.3.2創(chuàng)建MFC的工作線程2.創(chuàng)建并啟動工作線程(S7.3.2創(chuàng)建MFC的工作線程CWinThread*AfxBeginThread(AFX_THREADPROCpfnThreadProc,//控制函數(shù)的地址LPVOIDpParam,//數(shù)據(jù)結(jié)構(gòu)的指針,傳數(shù)據(jù)給線程控制函數(shù)intpPriority=THREAD_PRIORITY_NORMAL,//優(yōu)先級UINTnStackSize=0,//線程的堆棧大?。ň彌_區(qū))DWORDdwCreateFlags=0,//線程的運行狀態(tài),是否被掛起LPSECURITY_ATTTRIBUTESlpSecurityAttrs=NULL//安全屬性);

后面4個參數(shù)為可選參數(shù)。2021/8/17187.3.2創(chuàng)建MFC的工作線程CWinThread*創(chuàng)建工作線程的例子3、創(chuàng)建工作線程的例子功能:求長度為N的數(shù)組Arry的各元素的和。編程實現(xiàn)線程控制函數(shù)(1)//首先定義了一個結(jié)構(gòu):struct{

intN;//數(shù)組元素的個數(shù)。

double*Arry;//指向一個雙精度實數(shù)的數(shù)組

}myData;

//定義了此結(jié)構(gòu)類型的變量,省略了初始化的代碼myDatass;

2021/8/1719創(chuàng)建工作線程的例子3、創(chuàng)建工作線程的例子2021/8/171創(chuàng)建工作線程的例子(2)//接著定義線程的控制函數(shù)。UINTMyCalcFunc(LPVOIDpParam){ //如果入口參數(shù)為空指針,終止線程。 if(pPara==NULL)AfxEndThread(MY_NULL_POINTER_ERROR); intN=pPara->N;//數(shù)組的元素個數(shù)。 double*Arry=pPara->Arry;//指向數(shù)組的第一個元素。 doublesum=0;//數(shù)組元素之和。 for(inti=0;i<N;i++)sum+=Arry[i];//求和。 CStringbb; bb.Format(“數(shù)組的和是:%d”,sum);//格式化顯示字符串。 AfxMessageBox(bb);//顯示結(jié)果。 return0; }改為:pPara

2021/8/1720創(chuàng)建工作線程的例子(2)//接著定義線程的控制函數(shù)。改為:創(chuàng)建工作線程的例子調(diào)用AfxBeginThread()來創(chuàng)建并啟動這個線程。將控制函數(shù)名和結(jié)構(gòu)變量的地址作為參數(shù)傳遞,其他的參數(shù)省略,使用默認值。AfxBeginThread(MyCalcFunc,&ss);一旦調(diào)用了此函數(shù),線程就被創(chuàng)建,并開始執(zhí)行線程函數(shù)。當(dāng)數(shù)據(jù)的計算完成時,函數(shù)將停止運行,相應(yīng)的線程也隨即終止。線程擁有的堆棧和其他資源都將釋放。CWinThread對象將被刪除。2021/8/1721創(chuàng)建工作線程的例子調(diào)用AfxBeginThread()來創(chuàng)建創(chuàng)建工作線程的例子4.創(chuàng)建工作線程的一般模式可以得出創(chuàng)建工作線程的一般模式:定義一個結(jié)構(gòu)myData用于傳遞數(shù)據(jù);工作線程控制函數(shù)的框架;UINTMyThreadProc(LPVOIDpPara){if(pPara==NULL){AfxEndThread(MY_NULL_POINTER_ERROR);

return1;

}2021/8/1722創(chuàng)建工作線程的例子4.創(chuàng)建工作線程的一般模式2021/8/1創(chuàng)建工作線程的例子 ……//利用入口參數(shù)作某些工作。 return0;//線程成功地完成并返回。 }在程序的另一個函數(shù)中插入以下代碼。 ..............

myDatass;

AfxBeginThread(MyThreadProc,ss);2021/8/1723創(chuàng)建工作線程的例子 ……//利用入口參數(shù)作某些工作。2027.3.3創(chuàng)建并啟動用戶界面線程用戶界面線程允許用戶使用更多的用戶界面對象,如對話框或其他窗口。因此,要使用用戶界面線程,需要做更多的工作:創(chuàng)建并啟動用戶界面線程要經(jīng)過三個步驟:從CWinThread類派生出自己的線程類;改造這個線程類,使它能夠完成用戶希望的工作創(chuàng)建并啟動用戶界面線程。2021/8/17247.3.3創(chuàng)建并啟動用戶界面線程用戶界面線程允許7.3.3創(chuàng)建并啟動用戶界面線程1、從CWinThread類派生出自己的線程類要創(chuàng)建一個用戶界面線程,首先從CWinThread類派生出自己的線程類,可借助ClassWizard來完成。

2、改造自己的線程類對這個派生的線程類作以下改造工作:在類的.h頭文件中,用DECLARE_DYNCREATE宏來聲明這個類(使其支持動態(tài)創(chuàng)建);DECLARE_DYNCREATE(class_name)2021/8/17257.3.3創(chuàng)建并啟動用戶界面線程1、從CWinThrea7.3.3創(chuàng)建并啟動用戶界面線程在類的.CPP文件中,用IMPLEMENT_DYNCREATE宏來實現(xiàn)這個類。調(diào)用格式是:IMPLEMENT_DYNCREATE(class_name,base_class_name)兩個參數(shù)分別是參數(shù)是線程類名和它的基類名。2021/8/17267.3.3創(chuàng)建并啟動用戶界面線程在類的.CPP文件中,用7.3.3創(chuàng)建并啟動用戶界面線程對派生類的改造:這個線程類須重載它的基類的某些成員函數(shù),如該類的InitInstance()成員函數(shù);對于其他成員函數(shù),可以有選擇地重載。創(chuàng)建新的用戶界面窗口類,并建立線程類與用戶界面窗口類的聯(lián)系。利用類向?qū)樾陆ǖ木€程類添加控件成員變量,添加響應(yīng)消息的成員函數(shù),編寫實現(xiàn)代碼。2021/8/17277.3.3創(chuàng)建并啟動用戶界面線程對派生類的改造:20217.3.3創(chuàng)建并啟動用戶界面線程成員函數(shù)說明ExitInstance線程終止時執(zhí)行InitInstance線程實例化時執(zhí)行OnIdle線程空閑時,一般不重載PreTranslateMessage消息派發(fā)前可以重新解釋消息Run線程控制函數(shù),消息循環(huán),不重載WinThread的成員函數(shù)包括:2021/8/17287.3.3創(chuàng)建并啟動用戶界面線程成員函數(shù)說明ExitIn7.3.3創(chuàng)建并啟動用戶界面線程3.創(chuàng)建并啟動用戶界面線程可以使用MFC提供的AfxBeginThread()函數(shù)的另一個創(chuàng)建并啟動用戶界面線程,調(diào)用格式是:CWinThread*AfxBeginThread(CRuntimeClass*pThreadClass,//繼承的線程類指針intpPriority=THREAD_PRIORITY_NORMAL,//優(yōu)先級UINTnStackSize=0,//創(chuàng)建線程的堆棧大小DWORDdwCreateFlags=0,//線程的狀態(tài)LPSECURITY_ATTTRIBUTESlpSecurityAttrs=NULL);2021/8/17297.3.3創(chuàng)建并啟動用戶界面線程3.創(chuàng)建并啟動用戶界面線7.3.3創(chuàng)建并啟動用戶界面線程4.AfxBeginThread()函數(shù)所作的工作它創(chuàng)建一個新的用戶自己的線程類的對象,該對象繼承了CWinThread類的屬性。MFC自動調(diào)用新線程類的InitInstance()函數(shù),來初始化這個新的線程類對象實例。調(diào)用CWinThread::CreateThread函數(shù)來開始執(zhí)行這個線程,并運行RUN函數(shù),進入消息循環(huán)。函數(shù)返回一個指向新生成的CWinThread對象的指針,可以把它保存在一個變量中,其它線程就可以利用這個指針來訪問該線程類的成員變量或成員函數(shù)。2021/8/17307.3.3創(chuàng)建并啟動用戶界面線程4.AfxBeginTh7.3.3創(chuàng)建并啟動用戶界面線程線程的消息循環(huán):系統(tǒng)自動地為每一個線程創(chuàng)建一個消息隊列,如果線程創(chuàng)建了一個或多個窗口,就必須提供一個消息循環(huán),這個消息循環(huán)從線程的消息隊列中獲取消息,并把它們發(fā)送到相應(yīng)的windows過程。

因為系統(tǒng)將消息導(dǎo)向獨立的應(yīng)用程序窗口,所以在開始線程的消息循環(huán)之前,線程必須至少創(chuàng)建一個窗口,大多數(shù)基于Win32的應(yīng)用程序包含一個單一的線程,該線程創(chuàng)建了若干窗口。2021/8/17317.3.3創(chuàng)建并啟動用戶界面線程線程的消息循環(huán):20217.3.4終止線程1、正常終止線程工作線程:線程控制函數(shù)代碼執(zhí)行完畢用戶線程:發(fā)送消息到窗口2、提前終止線程利用AfxEndThread(UNITnExitCode)函數(shù)參數(shù)為線程的終止代碼,該函數(shù)應(yīng)該在線程內(nèi)部調(diào)用;3、終止線程的另一種方法TerminateThread()函數(shù)強行終止。2021/8/17327.3.4終止線程1、正常終止線程2021/8/17324、獲取線程的終止代碼BoolGetExitCodeThread(HANDLEhThread,//線程句柄LPDWORDlpExitCode//接收線程的終止代碼)5、設(shè)置線程的優(yōu)先級SetThreadPriority(HANDLEhThread,//線程句柄intnPriority//優(yōu)先級水平)2021/8/17334、獲取線程的終止代碼2021/8/1733多線程編程實例2021/8/1734多線程編程實例2021/8/1734第8章Winsock的輸入/輸出模型2021/8/1735第8章Winsock的輸入/輸出模型2021/8/173

第7章提到,WinSock在進行輸入輸出的時候,可以采用阻塞模式或非阻塞模式。使用非阻塞套接字,帶有I/O操作的隨機性,使非阻塞套接字難于操作,給編程帶來困難。為了解決這個問題,對于非阻塞的套接字工作模式,進一步引入了五種“套接字I/O模型”,它們有助于應(yīng)用程序通過一種異步方式,同時對一個或多個套接字上進行的通信加以管理。

2021/8/1736第7章提到,WinSock在進行輸入輸出的時候,可這些模型包括:select(選擇)、WSAAsyncSelect(異步選擇)、WSAEventSelect(事件選擇)、OverlappedI/O(重疊式I/O)Completionport(完成端口)。本章將主要介紹前三種。2021/8/1737這些模型包括:2021/8/1737不同的Windows平臺支持不同的I/O模型。如表8.1:2021/8/1738不同的Windows平臺支持不同的I/O模型。如表8.1:28.1select模型select(選擇)模型是Winsock中最常見的I/O模型。它的中心思想是利用select函數(shù),實現(xiàn)對多個套接字I/O的管理。利用select函數(shù),可以判斷套接字上是否存在數(shù)據(jù),或者能否向一個套接字寫入數(shù)據(jù)。只有在條件滿足時,才對套接字進行輸入輸出操作,從而避免無功而返的I/O函數(shù)調(diào)用,避免頻繁產(chǎn)生WSAEWOULDBLOCK錯誤,使輸入輸出變得有序。2021/8/17398.1select模型select(選擇)模型是1.select的函數(shù)select的函數(shù)原型如下,其中fd_set數(shù)據(jù)類型,代表著一系列特定套接字的集合。intselect( intnfds, fd_setFAR*readfds, fd_setFAR*writefds, fd_setFAR*exceptfds, conststructtimevalFAR*timeout

);2021/8/17401.select的函數(shù)2021/8/1740說明:

select函數(shù)對readfds、writefds和exceptfds三個集合中指定的套接字進行檢查,看是否有數(shù)據(jù)可讀、可寫或有帶外數(shù)據(jù),如果有至少一個套接字符合條件,就立即返回。符合條件的套接字仍在集合中,不符合條件的套接字則被刪去。如果一個也沒有,則等待。但最多等待timeout所指定的時間,便返回。2021/8/1741說明:2021/8/17412.操作套接字集合的宏在程序中,用select對套接字進行監(jiān)視之前,必須先將要檢查的套接字句柄分配給某個集合,設(shè)置好相應(yīng)的fd_set結(jié)構(gòu),再來調(diào)用select函數(shù),便可知道一個套接字上是否正在發(fā)生上述的I/O活動。Winsock提供了下列宏操作,專門對fd_set數(shù)據(jù)類型進行操作FD_CLR(s,*set):從set中刪除套接字s。2021/8/17422.操作套接字集合的宏2021/8/1742FD_ISSET(s,*set):檢查s是否set集合的一名成員;如答案是肯定的是,則返回TRUE。FD_SET(s,*set):將套接字s加入集合set。FD_ZERO(*set):將set初始化成空集合。其中,參數(shù)s是一個要檢查的套接字,參數(shù)set是一個fd_set集合類型的指針。例如:調(diào)用select函數(shù)前,可使用FD_SET宏將指定的套接字加入到fd_read集合中,select函數(shù)完成后,可使用FD_ISSET宏,來檢查該套接字是否仍在fd_read集合中。2021/8/1743FD_ISSET(s,*set):檢查s是否set集合的一3.select模型的操作步驟使用FD_ZERO宏初始化感興趣的每一個fd_set集合。使用FD_SET宏將要檢查的套接字句柄添加到感興趣的每個fd_set集合中,相當(dāng)在指定的fd_set集合中,設(shè)置好要檢查的I/O活動。調(diào)用select函數(shù),然后等待。select完成并返回后,會修改每個fd_set結(jié)構(gòu),刪除那些不存在待決I/O操作的套接字句柄,在各個fd_set集合中返回符合條件的套接字。2021/8/17443.select模型的操作步驟2021/8/1744根據(jù)select的返回值,使用FD_ISSET宏,對每個fd_set集合進行檢查,判斷一個特定的套接字是否仍在集合中,便可判斷出哪些套接字存在著尚未完成(待決)的I/O操作。知道了每個集合中“待決”的I/O操作之后,對相應(yīng)的套接字的I/O進行處理,然后返回步驟1,繼續(xù)進行select處理。2021/8/1745根據(jù)select的返回值,使用FD_ISSET宏,對每個f4.舉例下面的例子用select管理一個套接字上的I/O操作:SOCKETs; //定義一個套接字fd_setfdread; //定義一個套接字集合變量intret; //返回值//創(chuàng)建一個套接字,并接受連接.......2021/8/17464.舉例2021/8/1746//管理該套接字上的輸入/輸出while(TRUE){

FD_ZERO(&fdread);//調(diào)用select()之前要清除套接字集合

FD_SET(s,&fdread);//將套接字s添加到fdread集合中 //調(diào)用select()函數(shù),并等待它的完成, //這里只是想檢查s是否有數(shù)據(jù)可讀

if((ret=select(0,&fdread,NULL,NULL,NULL))== SOCKET_ERROR) {

……//處理錯誤的代碼

}

2021/8/1747//管理該套接字上的輸入/輸出2021/8/1747//返回值大于零,說明有符合條件的套接字//對于本例這個簡單的情況,select()的返回值應(yīng)是1。//如果程序處理更多的套接字,返回值可能大于1,//應(yīng)用程序應(yīng)檢查特定的套接字是否在返回的集合中if(ret>0){if(FD_ISSET(s,&fdread)){

……//對該套接字進行讀操作}}}2021/8/1748//返回值大于零,說明有符合條件的套接字2021/8/1748.2WSAAsyncSelect異步I/O模型異步I/O模型通過調(diào)用WSAAsyncSelect函數(shù)實現(xiàn)。利用這個模型,應(yīng)用程序可在一個套接字上,接收以Windows消息為基礎(chǔ)的網(wǎng)絡(luò)事件通知。該模型最早出現(xiàn)于Winsock的1.1中,以適應(yīng)其多任務(wù)消息環(huán)境。2021/8/17498.2WSAAsyncSelect異步I/O模型1.WSAAsyncSelect函數(shù)函數(shù)的定義是: intWSAAsyncSelect( SOCKETs, HWNDhWnd, unsignedintwMsg, longlEvent );2021/8/17501.WSAAsyncSelect函數(shù)2021/8/17502.窗口回調(diào)例程應(yīng)用程序在一個套接字上調(diào)用WSAAsyncSelect函數(shù)時,該函數(shù)的hWnd參數(shù)指定了一個窗口句柄。函數(shù)成功調(diào)用后,當(dāng)指定的網(wǎng)絡(luò)事件發(fā)生時,會自動執(zhí)行該窗口對應(yīng)的窗口回調(diào)例程。并將網(wǎng)絡(luò)事件通知和Windows消息的相關(guān)信息,傳遞給該例程的入口參數(shù),用戶可以在該例程中添加自己的代碼,針對不同的網(wǎng)絡(luò)事件進行處理,從而實現(xiàn)有序的套接字輸入和輸出。2021/8/17512.窗口回調(diào)例程2021/8/1751窗口回調(diào)例程應(yīng)定義成如下形式:LRESULTCALLBACKWindowProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam);

2021/8/1752窗口回調(diào)例程應(yīng)定義成如下形式:2021/8/17523.舉例2021/8/17533.舉例2021/8/17538.3WSAEventSelect事件選擇模型WSAEventSelect事件選擇模型和WSAAsyncSelect模型類似,它也允許程序在一個或多個套接字上,接收以事件為基礎(chǔ)的網(wǎng)絡(luò)事件通知。表8.2總結(jié)的由WSAAsyncSelect模型采用的網(wǎng)絡(luò)事件,均可原封不動地移植到事件選擇模型中。也就是說,在用新模型開發(fā)的應(yīng)用程序中,也能接收和處理所有那些事件。該模型最主要的差別在于,網(wǎng)絡(luò)事件會投遞至一個事件對象句柄,而非投遞至一個窗口例程。以下按照使用此模型的編程步驟介紹。

2021/8/17548.3WSAEventSelect事件選擇模型W1.創(chuàng)建事件對象句柄事件選擇模型要求應(yīng)用程序針對每一個套接字,首先創(chuàng)建一個事件對象。方法是調(diào)用WSACreateEvent函數(shù),它的定義如下:WSAEVENTWSACreateEvent(void);

返回值:一個創(chuàng)建好的事件對象句柄。

2021/8/17551.創(chuàng)建事件對象句柄2021/8/17552.關(guān)聯(lián)套接字和事件對象,注冊關(guān)心的網(wǎng)絡(luò)事件有了事件對象句柄后,接下來將其與某個套接字關(guān)聯(lián)在一起,同時注冊感興趣的網(wǎng)絡(luò)事件類型(表8-2),這就需要調(diào)用WSAEventSelect函數(shù):intWSAEventSelect( SOCKETs, WSAEVENThEventObject, longlNetworkEvents );2021/8/17562.關(guān)聯(lián)套接字和事件對象,注冊關(guān)心的網(wǎng)絡(luò)事件2021/8/13.等待網(wǎng)絡(luò)事件觸發(fā)事件對象句柄的工作狀態(tài)套接字同一個事件對象句柄關(guān)聯(lián)在一起以后,程序便調(diào)用WSAWaitForMultipleEvents函數(shù),等待網(wǎng)絡(luò)事件觸發(fā)事件對象句柄的工作狀態(tài):DWORDWSAWaitForMultipleEvents( DWORDcEvents, constWSAEVENTFAR*lphEvents, BOOLfWaitAll, DWORDdwTimeout, BOOLfAlertable );該函數(shù)用來等待一個或多個事件對象句柄,當(dāng)其中一個或所有句柄進入“已傳信”狀態(tài)后,或在超過了一個規(guī)定的時間期限后,立即返回。2021/8/17573.等待網(wǎng)絡(luò)事件觸發(fā)事件對象句柄的工作狀態(tài)2021/8/14.檢查套接字上所發(fā)生的網(wǎng)絡(luò)事件類型知道了造成網(wǎng)絡(luò)事件的套接字后,接下來可調(diào)用WSAEnumNetworkEvents函數(shù),檢查套接字上發(fā)生了什么類型的網(wǎng)絡(luò)事件。該函數(shù)定義如下:intWSAEnumNetworkEvents( SOCKETs, WSAEVENThEventObject, LPWSANETWORKEVENTSlpNetworkEvents);2021/8/17584.檢查套接字上所發(fā)生的網(wǎng)絡(luò)事件類型2021/8/17585.處理網(wǎng)絡(luò)事件在確定了套接字上發(fā)生的網(wǎng)絡(luò)事件類型后,可以根據(jù)不同的情況做出相應(yīng)的處理。完成了對WSANETWORKEVENTS結(jié)構(gòu)中的事件的處理之后,應(yīng)用程序應(yīng)在所有可用的套接字上,繼續(xù)等待更多的網(wǎng)絡(luò)事件。完成了對一個事件對象的處理后,應(yīng)調(diào)用WSACloseEvent函數(shù),釋放由事件句柄使用的系統(tǒng)資源。函數(shù)的定義如下:BOOLWSACloseEvent(WSAEVENThEvent);該函數(shù)也將一個事件句柄作為自己唯一的參數(shù),并會在成功后返回TRUE,失敗后返回FALSE。2021/8/17595.處理網(wǎng)絡(luò)事件2021/8/17596.舉例

2021/8/17606.舉例2021/8/17608.4其他模型重疊I/O模型在Winsock中,能使應(yīng)用程序達到更佳的性能。重疊模型的基本原理是讓應(yīng)用程序使用一個重疊的數(shù)據(jù)結(jié)構(gòu),一次投遞一個或多個Winsock的I/O請求。針對那些提交的請求,在它們完成之后,應(yīng)用程序可為它們提供服務(wù)。自Winsock2.0發(fā)布開始,重疊I/O便已集成到新的Winsock函數(shù)中。因此,重疊I/O模型適用于安裝了Winsock2.0的所有Windows平臺。2021/8/17618.4其他模型重疊I/O模型2021/8/1761“完成端口”模型

是迄今為止最為復(fù)雜的一種I/O模型。然而,假若一個應(yīng)用程序同時需要管理為數(shù)眾多的套接字,那么采用這種模型,往往可以達到最佳的系統(tǒng)性能!該模型只適用于WindowsNT和Windows2000操作系統(tǒng)。因其設(shè)計的復(fù)雜性,只有在你的應(yīng)用程序需要同時管理數(shù)百乃至上千個套接字的時候,而且希望隨著系統(tǒng)內(nèi)安裝的CPU數(shù)量的增多,應(yīng)用程序的性能也可以線性提升時,才應(yīng)考慮采用“完成端口”模型。2021/8/1762“完成端口”模型2021/8/1762網(wǎng)絡(luò)編程實用教程第7章WinSock的多線程編程2021/8/1763網(wǎng)絡(luò)編程實用教程第7章WinSock的多線程編程2021本章內(nèi)容:WinSock需要多線程編程的原因:Win32操作系統(tǒng)下的多進程多線程機制、多線程機制在網(wǎng)絡(luò)編程中的應(yīng)用和VisualC++6.0對多線程網(wǎng)絡(luò)編程的支持。分析了MFC支持的兩種線程,給出了創(chuàng)建MFC的工作線程、創(chuàng)建并啟動用戶界面線程和終止線程的步驟。2021/8/1764本章內(nèi)容:2021/8/1727.1WinSock為什么需要多線程編程2021/8/17657.1WinSock為什么需要多線程編程2021/8/17.1.1WinSock的兩種輸入輸出模式如前所述,WinSock在進行輸入輸出的時候,可以使用兩種工作模式:“阻塞”模式:又稱為同步模式“非阻塞”模式:又稱為異步模式

工作在“阻塞”模式下的套接字被稱為阻塞套接字,而工作在“非阻塞”模式下的套接字稱為非阻塞套接字。2021/8/17667.1.1WinSock的兩種輸入輸出模式如前所7.1.2兩種模式的優(yōu)缺點及解決方法“阻塞”與“非阻塞”模式的優(yōu)點和缺點:阻塞套接字的I/O操作工作情況比較確定,即調(diào)用、等待、返回。大部分情況下,I/O操作都能成功地完成,只是花費了等待的時間,容易編程;需要建立多個套接字連接來為多個客戶服務(wù)的時候,或在數(shù)據(jù)的收發(fā)量不均勻的時候,或在輸入輸出的時間不確定的時候,阻塞套接字的性能低下,甚至無能為力。2021/8/17677.1.2兩種模式的優(yōu)缺點及解決方法“阻塞”與“非阻塞”使用非阻塞套接字,需要編寫更多的代碼,因為必須恰當(dāng)?shù)匕盐照{(diào)用I/O函數(shù)的時機,盡量減少無功而返的調(diào)用,還必須詳加分析每個Winsock調(diào)用中收到的錯誤,采取相應(yīng)的對策,這種I/O操作的隨機性使得非阻塞套接字顯得難于操作。所以必須采取適當(dāng)?shù)膶Σ?,讓阻塞和非阻塞套接字能夠滿足各種場合的要求。對于非阻塞工作模式:引入了五種“套接字I/O模型”。阻塞的工作模式,則引入了多線程機制。2021/8/1768使用非阻塞套接字,需要編寫更多的代碼,因為必須恰當(dāng)?shù)匕盐照{(diào)用7.2Win32操作系統(tǒng)下的多進程多線程機制2021/8/17697.2Win32操作系統(tǒng)下的多進程多線程機制2021/87.2.2Win32OS支持多線程應(yīng)用程序、進程及線程的關(guān)系DOS是單用戶單任務(wù)的。

Win32操作系統(tǒng)是多任務(wù)的,并且支持一個進程中有多個線程。一個線程(thread)是進程內(nèi)的一條執(zhí)行路徑,是一個應(yīng)用程序中的一條可執(zhí)行路徑。一個進程中至少要有一個線程,稱為主線程。當(dāng)啟動了一個應(yīng)用程序時,操作系統(tǒng)將為它創(chuàng)建了一個進程,同時創(chuàng)建該進程的主線程,并開始執(zhí)行主線程。主線程可以創(chuàng)建并啟動其他輔助線程,由主線程創(chuàng)建的線程又可以創(chuàng)建并啟動更多的線程。2021/8/17707.2.2Win32OS支持多線程應(yīng)用程序、進程及線程7.2.2Win32OS支持多線程單CPU分時地運行進程中的各個線程2021/8/17717.2.2Win32OS支持多線程單CPU分時地運行進7.2.3多線程機制在網(wǎng)絡(luò)編程中的應(yīng)用如果一個應(yīng)用程序,有多個任務(wù)需要同時進行處理,則適合使用多線程機制。對于網(wǎng)絡(luò)上客戶機軟件:采用多線程,能克服在單線程的編程模式下,由于阻塞等待而產(chǎn)生的客戶程序就不能及時響應(yīng)用戶的操作命令的問題。對于網(wǎng)絡(luò)上服務(wù)器軟件:采用多線程的編程技術(shù),能更好地為多個客戶服務(wù)。對于一個客戶:采用多線程機制也能大大提高應(yīng)用程序的運行效率。網(wǎng)絡(luò)在線實時監(jiān)控軟件:2021/8/17727.2.3多線程機制在網(wǎng)絡(luò)編程中的應(yīng)用如果一個應(yīng)7.3VC6.0對多線程網(wǎng)絡(luò)編程的支持VC6.0環(huán)境下,兩種開發(fā)程序的方法:直接使用Win32API來編寫Win32應(yīng)用程序利用MFC基礎(chǔ)類庫編寫C++風(fēng)格的應(yīng)用程序。在這兩種Windows應(yīng)用程序的開發(fā)方式下,多線程的編程原理是一致的。2021/8/17737.3VC6.0對多線程網(wǎng)絡(luò)編程的支持VC6.0環(huán)境下7.3.1MFC支持的兩種線程微軟的基礎(chǔ)類庫MFC提供了對于多線程應(yīng)用程序的支持。在MFC中,線程分為兩種:用戶接口線程:(user-interfacethread),或稱用戶界面線程;工作線程:(theworkerthread),這兩類線程可以滿足不同任務(wù)的處理需求。2021/8/17747.3.1MFC支持的兩種線程微軟的基礎(chǔ)類庫MF1、用戶接口線程

作用:用于處理用戶的輸入,響應(yīng)用戶產(chǎn)生的消息。MFC為用戶接口線程提供了一個消息泵。同時包含一個消息循環(huán),以應(yīng)對各種事件。

MFC應(yīng)用程序的CWinApp類對象是一個典型的用戶接口線程在MFC應(yīng)用程序中,CWinThread是用戶接口線程的基類,CWinApp就是從CWinThread類派生出來的,編寫用戶接口線程候,也需要從CWinThread類派生。2021/8/17751、用戶接口線程2021/8/17132.工作線程

工作線程(workerthread),適用于處理那些不要求用戶輸入并且比較消耗時間的其他任務(wù)。對用戶來說,工作線程運行在后臺。這就使得工作線程特別適合去等待一個事件的發(fā)生。CWinThread類同樣是工作線程的基類。在編寫工作線程的時候,可以調(diào)用MFC的AfxBeginThread函數(shù),來創(chuàng)建CWinThread對象。2021/8/17762.工作線程2021/8/17147.3.2創(chuàng)建MFC的工作線程利用MFC創(chuàng)建工作線程的步驟:第一步:編程實現(xiàn)控制函數(shù)第二步:創(chuàng)建并啟動工作線程一般不必從CWinThread派生一個類。如果需要一個特定版本的CWinThread類,也可以去派生;但對于大多數(shù)的工作線程是不要求的??梢圆蛔魅魏涡薷牡厥褂肅WinThread類。2021/8/17777.3.2創(chuàng)建MFC的工作線程利用MFC創(chuàng)建工作線程的步7.3.2創(chuàng)建MFC的工作線程1、編程實現(xiàn)控制函數(shù)一個工作線程對應(yīng)一個控制函數(shù)。線程執(zhí)行的任務(wù)都應(yīng)編寫在控制函數(shù)之中,規(guī)定了該線程的執(zhí)行代碼,當(dāng)控制函數(shù)執(zhí)行結(jié)束而退出時,線程也就隨之終止。編寫工作線程的控制函數(shù)必須遵守一定的格式,控制函數(shù)的原型聲明是:UINTControlFunctionName(LPVOIDpParam);

pParam是一個數(shù)據(jù)結(jié)構(gòu);2021/8/17787.3.2創(chuàng)建MFC的工作線程1、編程實現(xiàn)控制函數(shù)2027.3.2創(chuàng)建MFC的工作線程2.創(chuàng)建并啟動工作線程(Startingthethread)

啟動線程:即開始運行它對應(yīng)的控制函數(shù)。在主線程或其他線程中調(diào)用AfxBeginThread()函數(shù)就可以創(chuàng)建新的線程,并使新線程開始運行。一般將線程的創(chuàng)建者稱為新線程的父線程。AfxBeginThread()函數(shù)有兩個重載的版本,區(qū)別在于使用的入口參數(shù)不同。2021/8/17797.3.2創(chuàng)建MFC的工作線程2.創(chuàng)建并啟動工作線程(S7.3.2創(chuàng)建MFC的工作線程CWinThread*AfxBeginThread(AFX_THREADPROCpfnThreadProc,//控制函數(shù)的地址LPVOIDpParam,//數(shù)據(jù)結(jié)構(gòu)的指針,傳數(shù)據(jù)給線程控制函數(shù)intpPriority=THREAD_PRIORITY_NORMAL,//優(yōu)先級UINTnStackSize=0,//線程的堆棧大?。ň彌_區(qū))DWORDdwCreateFlags=0,//線程的運行狀態(tài),是否被掛起LPSECURITY_ATTTRIBUTESlpSecurityAttrs=NULL//安全屬性);

后面4個參數(shù)為可選參數(shù)。2021/8/17807.3.2創(chuàng)建MFC的工作線程CWinThread*創(chuàng)建工作線程的例子3、創(chuàng)建工作線程的例子功能:求長度為N的數(shù)組Arry的各元素的和。編程實現(xiàn)線程控制函數(shù)(1)//首先定義了一個結(jié)構(gòu):struct{

intN;//數(shù)組元素的個數(shù)。

double*Arry;//指向一個雙精度實數(shù)的數(shù)組

}myData;

//定義了此結(jié)構(gòu)類型的變量,省略了初始化的代碼myDatass;

2021/8/1781創(chuàng)建工作線程的例子3、創(chuàng)建工作線程的例子2021/8/171創(chuàng)建工作線程的例子(2)//接著定義線程的控制函數(shù)。UINTMyCalcFunc(LPVOIDpParam){ //如果入口參數(shù)為空指針,終止線程。 if(pPara==NULL)AfxEndThread(MY_NULL_POINTER_ERROR); intN=pPara->N;//數(shù)組的元素個數(shù)。 double*Arry=pPara->Arry;//指向數(shù)組的第一個元素。 doublesum=0;//數(shù)組元素之和。 for(inti=0;i<N;i++)sum+=Arry[i];//求和。 CStringbb; bb.Format(“數(shù)組的和是:%d”,sum);//格式化顯示字符串。 AfxMessageBox(bb);//顯示結(jié)果。 return0; }改為:pPara

2021/8/1782創(chuàng)建工作線程的例子(2)//接著定義線程的控制函數(shù)。改為:創(chuàng)建工作線程的例子調(diào)用AfxBeginThread()來創(chuàng)建并啟動這個線程。將控制函數(shù)名和結(jié)構(gòu)變量的地址作為參數(shù)傳遞,其他的參數(shù)省略,使用默認值。AfxBeginThread(MyCalcFunc,&ss);一旦調(diào)用了此函數(shù),線程就被創(chuàng)建,并開始執(zhí)行線程函數(shù)。當(dāng)數(shù)據(jù)的計算完成時,函數(shù)將停止運行,相應(yīng)的線程也隨即終止。線程擁有的堆棧和其他資源都將釋放。CWinThread對象將被刪除。2021/8/1783創(chuàng)建工作線程的例子調(diào)用AfxBeginThread()來創(chuàng)建創(chuàng)建工作線程的例子4.創(chuàng)建工作線程的一般模式可以得出創(chuàng)建工作線程的一般模式:定義一個結(jié)構(gòu)myData用于傳遞數(shù)據(jù);工作線程控制函數(shù)的框架;UINTMyThreadProc(LPVOIDpPara){if(pPara==NULL){AfxEndThread(MY_NULL_POINTER_ERROR);

return1;

}2021/8/1784創(chuàng)建工作線程的例子4.創(chuàng)建工作線程的一般模式2021/8/1創(chuàng)建工作線程的例子 ……//利用入口參數(shù)作某些工作。 return0;//線程成功地完成并返回。 }在程序的另一個函數(shù)中插入以下代碼。 ..............

myDatass;

AfxBeginThread(MyThreadProc,ss);2021/8/1785創(chuàng)建工作線程的例子 ……//利用入口參數(shù)作某些工作。2027.3.3創(chuàng)建并啟動用戶界面線程用戶界面線程允許用戶使用更多的用戶界面對象,如對話框或其他窗口。因此,要使用用戶界面線程,需要做更多的工作:創(chuàng)建并啟動用戶界面線程要經(jīng)過三個步驟:從CWinThread類派生出自己的線程類;改造這個線程類,使它能夠完成用戶希望的工作創(chuàng)建并啟動用戶界面線程。2021/8/17867.3.3創(chuàng)建并啟動用戶界面線程用戶界面線程允許7.3.3創(chuàng)建并啟動用戶界面線程1、從CWinThread類派生出自己的線程類要創(chuàng)建一個用戶界面線程,首先從CWinThread類派生出自己的線程類,可借助ClassWizard來完成。

2、改造自己的線程類對這個派生的線程類作以下改造工作:在類的.h頭文件中,用DECLARE_DYNCREATE宏來聲明這個類(使其支持動態(tài)創(chuàng)建);DECLARE_DYNCREATE(class_name)2021/8/17877.3.3創(chuàng)建并啟動用戶界面線程1、從CWinThrea7.3.3創(chuàng)建并啟動用戶界面線程在類的.CPP文件中,用IMPLEMENT_DYNCREATE宏來實現(xiàn)這個類。調(diào)用格式是:IMPLEMENT_DYNCREATE(class_name,base_class_name)兩個參數(shù)分別是參數(shù)是線程類名和它的基類名。2021/8/17887.3.3創(chuàng)建并啟動用戶界面線程在類的.CPP文件中,用7.3.3創(chuàng)建并啟動用戶界面線程對派生類的改造:這個線程類須重載它的基類的某些成員函數(shù),如該類的InitInstance()成員函數(shù);對于其他成員函數(shù),可以有選擇地重載。創(chuàng)建新的用戶界面窗口類,并建立線程類與用戶界面窗口類的聯(lián)系。利用類向?qū)樾陆ǖ木€程類添加控件成員變量,添加響應(yīng)消息的成員函數(shù),編寫實現(xiàn)代碼。2021/8/17897.3.3創(chuàng)建并啟動用戶界面線程對派生類的改造:20217.3.3創(chuàng)建并啟動用戶界面線程成員函數(shù)說明ExitInstance線程終止時執(zhí)行InitInstance線程實例化時執(zhí)行OnIdle線程空閑時,一般不重載PreTranslateMessage消息派發(fā)前可以重新解釋消息Run線程控制函數(shù),消息循環(huán),不重載WinThread的成員函數(shù)包括:2021/8/17907.3.3創(chuàng)建并啟動用戶界面線程成員函數(shù)說明ExitIn7.3.3創(chuàng)建并啟動用戶界面線程3.創(chuàng)建并啟動用戶界面線程可以使用MFC提供的AfxBeginThread()函數(shù)的另一個創(chuàng)建并啟動用戶界面線程,調(diào)用格式是:CWinThread*AfxBeginThread(CRuntimeClass*pThreadClass,//繼承的線程類指針intpPriority=THREAD_PRIORITY_NORMAL,//優(yōu)先級UINTnStackSize=0,//創(chuàng)建線程的堆棧大小DWORDdwCreateFlags=0,//線程的狀態(tài)LPSECURITY_ATTTRIBUTESlpSecurityAttrs=NULL);2021/8/17917.3.3創(chuàng)建并啟動用戶界面線程3.創(chuàng)建并啟動用戶界面線7.3.3創(chuàng)建并啟動用戶界面線程4.AfxBeginThread()函數(shù)所作的工作它創(chuàng)建一個新的用戶自己的線程類的對象,該對象繼承了CWinThread類的屬性。MFC自動調(diào)用新線程類的InitInstance()函數(shù),來初始化這個新的線程類對象實例。調(diào)用CWinThread::CreateThread函數(shù)來開始執(zhí)行這個線程,并運行RUN函數(shù),進入消息循環(huán)。函數(shù)返回一個指向新生成的CWinThread對象的指針,可以把它保存在一個變量中,其它線程就可以利用這個指針來訪問該線程類的成員變量或成員函數(shù)。2021/8/17927.3.3創(chuàng)建并啟動用戶界面線程4.AfxBeginTh7.3.3創(chuàng)建并啟動用戶界面線程線程的消息循環(huán):系統(tǒng)自動地為每一個線程創(chuàng)建一個消息隊列,如果線程創(chuàng)建了一個或多個窗口,就必須提供一個消息循環(huán),這個消息循環(huán)從線程的消息隊列中獲取消息,并把它們發(fā)送到相應(yīng)的windows過程。

因為系統(tǒng)將消息導(dǎo)向獨立的應(yīng)用程序窗口,所以在開始線程的消息循環(huán)之前,線程必須至少創(chuàng)建一個窗口,大多數(shù)基于Win32的應(yīng)用程序包含一個單一的線程,該線程創(chuàng)建了若干窗口。2021/8/17937.3.3創(chuàng)建并啟動用戶界面線程線程的消息循環(huán):20217.3.4終止線程1、正常終止線程工作線程:線程控制函數(shù)代碼執(zhí)行完畢用戶線程:發(fā)送消息到窗口2、提前終止線程利用AfxEndThread(UNITnExitCode)函數(shù)參數(shù)為線程的終止代碼,該函數(shù)應(yīng)該在線程內(nèi)部調(diào)用;3、終止線程的另一種方法TerminateThread()函數(shù)強行終止。2021/8/17947.3.4終止線程1、正常終止線程2021/8/17324、獲取線程的終止代碼BoolGetExitCodeThread(HANDLEhThread,//線程句柄LPDWORDlpExitCode//接收線程的終止代碼)5、設(shè)置線程的優(yōu)先級SetThreadPriority(HANDLEhThread,//線程句柄intnPriority//優(yōu)先級水平)2021/8/17954、獲取線程的終止代碼2021/8/1733多線程編程實例2021/8/1796多線程編程實例2021/8/1734第8章Winsock的輸入/輸出模型2021/8/1797第8章Winsock的輸入/輸出模型2021/8/173

第7章提到,WinSock在進行輸入輸出的時候,可以采用阻塞模式或非阻塞模式。使用非阻塞套接字,帶有I/O操作的隨機性,使非阻塞套接字難于操作,給編程帶來困難。為了解決這個問題,對于非阻塞的套接字工作模式,進一步引入了五種“套接字I/O模型”,它們有助于應(yīng)用程序通過一種異步方式,同時對一個或多個套接字上進行的通信加以管理。

2021/8/1798第7章提到,WinSock在進行輸入輸出的時候,可這些模型包括:select(選擇)、WSAAsyncSelect(異步選擇)、WSAEventSelect(事件選擇)、OverlappedI/O(重疊式I/O)Completionport(完成端口)。本章將主要介紹前三種。2021/8/1799這些模型包括:2021/8/1737不同的Windows平臺支持不同的I/O模型。如表8.1:2021/8/17100不同的Windows平臺支持不同的I/O模型。如表8.1:28.1select模型select(選擇)模型是Winsock中最常見的I/O模型。它的中心思想是利用select函數(shù),實現(xiàn)對多個套接字I/O的管理。利用select函數(shù),可以判斷套接字上是否存在數(shù)據(jù),或者能否向一個套接字寫入數(shù)據(jù)。只有在條件滿足時,才對套接字進行輸入輸出操作,從而避免無功而返的I/O函數(shù)調(diào)用,避免頻繁產(chǎn)生WSAEWOULDBLOCK錯誤,使輸入輸出變得有序。2021/8/171018.1select模型select(選擇)模型是1.select的函數(shù)select的函數(shù)原型如下,其中fd_set數(shù)據(jù)類型,代表著一系列特定套接字的集合。intselect( intnfds, fd_setFAR*readfds, fd_setFAR*writefds, fd_setFAR*exceptfds, conststructtimevalFAR*timeout

);2021/8/171021.select的函數(shù)2021/8/1740說明:

select函數(shù)對readfds、writefds和exceptfds三個集合中指定的套接字進行檢查,看是否有數(shù)據(jù)可讀、可寫或有帶外數(shù)據(jù),如果有至少一個套接字符合條件,就立即返回。符合條件的套接字仍在集合中,不符合條件的套接字則被刪去。如果一個也沒有,則等待。但最多等待timeout所指定的時間,便返回。2021/8/17103說明:2021/8/17412.操作套接字集合的宏在程序中,用select對套接字進行監(jiān)視之前,必須先將要檢查的套接字句柄分配給某個集合,設(shè)置好相應(yīng)的fd_set結(jié)構(gòu),再來調(diào)用select函數(shù),便可知道一個套接字上是否正在發(fā)生上述的I/O活動。Winsock提供了下列宏操作,專門對fd_set數(shù)據(jù)類型進行操作FD_CLR(s,*set):從set中刪除套接字s。2021/8/171042.操作套接字集合的宏2021/8/1742FD_ISSET(s,*set):檢查s是否set集合的一名成員;如答案是肯定的是,則返回TRUE。FD_SET(s,*set):將套接字s加入集合set。FD_ZERO(*set):將set初始化成空集合。其中,參數(shù)s是一個要檢查的套接字,參數(shù)set是一個fd_set集合類型的指針。例如:調(diào)用select函數(shù)前,可使用FD_SET宏將指定的套接字加入到fd_read集合中,select函數(shù)完成后,可使用FD_ISSET宏,來檢查該套接字是否仍在fd_read集合中。2021/8/17105FD_ISSET(s,*set):檢查s是否set集合的一3.select模型的操作步驟使用FD_ZERO宏初始化感興趣的每一個fd_set集合。使用FD_SET宏將要檢查的套接字句柄添加到感興趣的每個fd_set集合中,相當(dāng)在指定的fd_set集合中,設(shè)置好要檢查的I/O活動。調(diào)用select函數(shù),然后等待。select完成并返回后,會修改每個fd_set結(jié)構(gòu),刪除那些不存在待決I/O操作的套接字句柄,在各個fd_set集合中返回符合條件的套接字。2021/8/171063.select模型的操作步驟2021/8/1744根據(jù)select的返回值,使用FD_ISSET宏,對每個fd_set集合進行檢查,判斷一個特定的套接字是否仍在集合中,便可判斷出哪些套接字存在著尚未完成(待決)的I/O操作。知道了每個集合中“待決”的I/O操作之后,對相應(yīng)的套接字的I/O進行處理,然后返回步驟1,繼續(xù)進行select處理。2021/8/17107根據(jù)select的返回值,使用FD_ISSET宏,對每個f4.舉例下面的例子用select管理一個套接字上的I/O操作:SOCKETs; //定義一個套接字fd_setfdread; //定義一個套接字集合變量intret; //返回值//創(chuàng)建一個套接字,并接受連接.......2021/8/171084.舉例2021/8/1746//管理該套接字上的輸入/輸出while(TRUE){

FD_ZERO(&fdread);//調(diào)用select()之前要清除套接字集合

FD_SET(s,&fdread);//將套接字s添加到fdread集合中 //調(diào)用select()函數(shù),并等待它的完成, //這里只是想檢查s是否有數(shù)據(jù)可讀

if((ret=select(0,&fdread,NULL,NULL,NULL))== SOCKET_ERROR) {

……//處理錯誤的代碼

}

2021/8/17109//管理該套接字上的輸入/輸出2021/8/1747//返回值大于零,說明有符合條件的套接字//對于本例這個簡單的情況,select()的返回值應(yīng)是1。//如果程序處理更多的套接字,返回值可能大于1,//應(yīng)用程序應(yīng)檢查特定的套接字是否在返回的集合中if(ret>0){if(FD_ISSET(s,&fdread)){

……//對該套接字進行讀操作}}}2021/8/17110//返回值大于零,說明有符合條件的套接字2021/8/1748.2WSAAsyncSelect異步I/O模型異步I/O模型通過調(diào)用WSAAsyncSelect函數(shù)實現(xiàn)。利用這個模型,應(yīng)用程序可在一個套接字上,接收以Windows消息為基礎(chǔ)的網(wǎng)絡(luò)事件通知。該模型最早出現(xiàn)于Winsock的1.1中,以適應(yīng)其多任務(wù)消息環(huán)境。2021/8/171118.2WSAAsyncSelect異步I/O模型1.WSAAsyncSelect函數(shù)函數(shù)的定義是: intWSAAsyncSelect( SOCKETs, HWNDhWnd

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論