• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            kenlistian

            厚積薄發(fā). 勤為槳,思為帆

               :: 首頁(yè) :: 新隨筆 ::  :: 聚合  :: 管理 ::
              73 隨筆 :: 4 文章 :: 22 評(píng)論 :: 0 Trackbacks

                 在網(wǎng)絡(luò)通訊中,由于網(wǎng)絡(luò)擁擠或一次發(fā)送的數(shù)據(jù)量過(guò)大等原因,經(jīng)常會(huì)發(fā)生交換的數(shù)據(jù)在短時(shí)間內(nèi)不能傳送完,收發(fā)數(shù)據(jù)的函數(shù)因此不能返回,這種現(xiàn)象叫做阻塞。 Winsock對(duì)有可能阻塞的函數(shù)提供了兩種處理方式:阻塞和非阻塞方式。

            阻塞模式

                 在阻塞方式下,收發(fā)數(shù)據(jù)的函數(shù)在被調(diào)用后一直要到傳送完畢或者出錯(cuò)才能返回。在阻塞期間,被阻的函數(shù)不會(huì)斷調(diào)用系統(tǒng)函數(shù)GetMessage()來(lái)保持消息循環(huán)的正常進(jìn)行。

            非阻塞模式
                    將一個(gè)套接字置為非阻塞模式之后, Winsock API調(diào)用會(huì)立即返回。一般這些調(diào)用都會(huì)“失敗”,并返回一個(gè)WSAEWOULDBLOCK。表明其操作在調(diào)用期間沒(méi)有時(shí)間完成。如在系統(tǒng)的輸入緩沖區(qū)中,并不存在等待的數(shù)據(jù),那recv調(diào)用就會(huì)返回WSAEWOULDBLOCK錯(cuò)誤。通常,我們需要重復(fù)調(diào)用同一個(gè)函數(shù),直至獲得一個(gè)成功返回代碼。這不是一個(gè)好的方法。通常采用Winsock的套接字I/O模型去處理。

            套接字I/O模型共有五種類型,如下:

              select(選擇) 
              WSAAsyncSelect(異步選擇)
              WSAEventSelect(事件選擇)
              overlapped(重疊)
              completion port(完成端口)

             

            *WSAAsyncSelect

                  Winsock通過(guò)WSAAsyncSelect()自動(dòng)地設(shè)置套接字處于非阻塞方式。使用WindowsSockets實(shí)現(xiàn)Windows網(wǎng)絡(luò)程序設(shè)計(jì)的關(guān)鍵就是它提供了對(duì)網(wǎng)絡(luò)事件基于消息的異步存取,用于注冊(cè)應(yīng)用程序感興趣的網(wǎng)絡(luò)事件。它請(qǐng)求Windows Sockets DLL在檢測(cè)到套接字上發(fā)生的網(wǎng)絡(luò)事件時(shí),向窗口發(fā)送一個(gè)消息。

             int PASCAL FAR WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);
            hWnd:窗口句柄
            wMsg:需要發(fā)送的消息
            lEvent:事件(以下為事件的內(nèi)容)
            值: 含義:
            FD_READ 期望在套接字上收到數(shù)據(jù)(即讀準(zhǔn)備好)時(shí)接到通知
            FD_WRITE 期望在套接字上可發(fā)送數(shù)據(jù)(即寫準(zhǔn)備好)時(shí)接到通知
            FD_OOB 期望在套接字上有帶外數(shù)據(jù)到達(dá)時(shí)接到通知
            FD_ACCEPT 期望在套接字上有外來(lái)連接時(shí)接到通知
            FD_CONNECT 期望在套接字連接建立完成時(shí)接到通知
            FD_CLOSE 期望在套接字關(guān)閉時(shí)接到通知

                   進(jìn)行異步選擇使用WSAAsyncSelect()函數(shù)時(shí),有以下幾點(diǎn)需要引起特別的注意:
             ?。B續(xù)使用兩次WSAAsyncSelect()函數(shù)時(shí),只有第二次設(shè)置的事件有效,如:
                       WSAAsyncSelect(s,hwnd,wMsg1,FD_READ);
                       WSAAsyncSelect(s,hwnd,wMsg2,FD_CLOSE);
                    這樣只有當(dāng)FD_CLOSE事件發(fā)生時(shí)才會(huì)發(fā)送wMsg2消息。
             ?。梢栽谠O(shè)置過(guò)異步選擇后通過(guò)再次調(diào)用WSAAsyncSelect(s,hwnd,0,0);的形式取消在套接字上所設(shè)置的異步事件。
             ?。甒indows Sockets DLL在一個(gè)網(wǎng)絡(luò)事件發(fā)生后,通常只會(huì)給相應(yīng)的應(yīng)用程序發(fā)送一個(gè)消息,而不能發(fā)送多個(gè)消息。但通過(guò)使用一些函數(shù)隱式地允許重發(fā)此事件的消息,這樣就可能再次接收到相應(yīng)的消息。
              .在調(diào)用過(guò)closesocket()函數(shù)關(guān)閉套接字之后不會(huì)再發(fā)生FD_CLOSE事件。


                 對(duì)UDP協(xié)議,這些網(wǎng)絡(luò)事件主要為:
                  FD_READ   期望在套接字收到數(shù)據(jù)(即讀準(zhǔn)備好)時(shí)接收通知;
                  FD_WRITE 期望在套接字可發(fā)送數(shù)(即寫準(zhǔn)備好)時(shí)接收通知;
                FD_CLOSE 期望在套接字關(guān)閉時(shí)接電通知
              消息變量wParam指示發(fā)生網(wǎng)絡(luò)事件的套接字,變量1Param的低字節(jié)描述發(fā)生的網(wǎng)絡(luò)事件,高字包含錯(cuò)誤碼。如在窗口函數(shù)的消息循環(huán)中均加一個(gè)分支:
            int ok=sizeof(SOCKADDR);
            case wMsg;
            switch(1Param)
            {
                case FD_READ:  //套接字上讀數(shù)據(jù) 
                if(recvfrom(sr.lpPlayData[j],dwDataSize,0,(struct sockaddr FAR*)&there1,
                 (int FAR*)&ok)==SOCKET_ERROR0) {
                            MessageBox(hwnd,“數(shù)據(jù)接收失敗!”,“”,MB_OK);
                            return(FALSE);
                   }
                case FD_WRITE:    //套接字上寫數(shù)據(jù)
              }
            break;

             

             

            *WSAEventSelect
                  事件通知模型要求在程序中針對(duì)使用的每個(gè)套接字創(chuàng)建一個(gè)事件對(duì)象,然后通過(guò)事件模式通知程序其套接字是否收到或發(fā)送的信息。一般來(lái)說(shuō)這種模式,一般就是通過(guò)類似調(diào)用waitformultipleObject一樣在一個(gè)線程中等待信號(hào)事件來(lái),來(lái)了就處理。具體調(diào)用的函數(shù)如下:

                創(chuàng)建WSACreateEvent函數(shù).該函數(shù)的返回值是一個(gè)創(chuàng)建好的事件對(duì)象句柄。事件對(duì)象句柄完后,接下來(lái)將其與某個(gè)套接字關(guān)聯(lián)在一起,同時(shí)注冊(cè)自己感興趣的網(wǎng)絡(luò)事件類型,方法是調(diào)用WSAEventSelect函數(shù),對(duì)它的定義如下:

               int WSAEventSelect (
                          SOCKET s,                              //需要非阻塞處理的套接字
                          WSAEVENT hEventObject,    //WSACreateEvent 創(chuàng)建來(lái)的,關(guān)聯(lián)到socket
                          long lNetworkEvents     
                           );
                lNetworkEvents,對(duì)應(yīng)一個(gè)“位掩碼”,用于指定應(yīng)用程序感興趣的各種網(wǎng)絡(luò)事件類型的一個(gè)組合。要想獲知對(duì)這些事件類型的詳細(xì)說(shuō)明,請(qǐng)參考早先討論過(guò)的WSAAsyncSelect I/O模型。
                  為WSAEventSelect創(chuàng)建的事件擁有兩種工作狀態(tài),以及兩種工作模式。
                兩種工作狀態(tài)分別是“已傳信”(signaled)和 “未傳信”(nonsignaled)。
                工作模式則包括“人工”(manual reset)和“自動(dòng)”(auto reset)。
                  

                  WSACreateEvent缺省時(shí)其信號(hào)狀態(tài)為0,且為人工設(shè)置,當(dāng)網(wǎng)絡(luò)事件觸發(fā)了與一個(gè)套接字關(guān)聯(lián)在一起的事件對(duì)象,其事件信號(hào)置1。在完成了一個(gè)I/O請(qǐng)求的處理之后,需要調(diào)用WSAResetEvent復(fù)位處理(置信號(hào)為0)。
                 一個(gè)套接字同一個(gè)事件對(duì)象句柄關(guān)聯(lián)在一起后,應(yīng)用程序便可開始I/O處理;方法是等待網(wǎng)絡(luò)事件觸發(fā)事件對(duì)象句柄的工作狀態(tài)。
                 一般而言,在等待網(wǎng)絡(luò)傳來(lái)事件時(shí),類似WaitforMultipleObject,其WSAWaitForMultipleEvents函數(shù)的設(shè)計(jì)宗旨便是用來(lái)等待一個(gè)或多個(gè)事件對(duì)象句柄,并在事先指定的一個(gè)或所有句柄進(jìn)入有信號(hào)狀態(tài)后,或在超過(guò)了一個(gè)規(guī)定的時(shí)間周期后,立即返回(線程往往在這里死等)。

               下面是 WSAWaitForMultipleEvents函數(shù)的定義:
            DWORD WSAWaitForMultipleEvents(
              DWORD cEvents,                 
              const WSAEVENT FAR *lphEvents
              BOOL fWaitAll,                 
              DWORD dwTimeOUT,               
              BOOL fAlertable                
            );

            其用法和WaitForMultipleObject類似。
            cEvents和lphEvents參數(shù)定義了由WSAEVENT對(duì)象構(gòu)成的一個(gè)數(shù)組。在這個(gè)數(shù)組中,cEvents指定的是事件對(duì)象的數(shù)量,而lphEvents對(duì)應(yīng)的是一個(gè)指針,用于直接引用該數(shù)組。
                 要注意的是, WSAWaitForMultipleEvents只能支持由WSA_MAXIMUM_WAIT_EVENTS對(duì)象規(guī)定的一個(gè)最大值,在此定義成64個(gè)。故該I/O模型一次最多都只能支持64個(gè)套接字。假如想讓這個(gè)模型同時(shí)管理不止64個(gè)套接字,必須創(chuàng)建更多的工作者線程,以便等待更多的事件對(duì)象。

            fWaitAl l 參數(shù)指定了WSAWaitForMultiple Events如何等待在事件數(shù)組中的對(duì)象。
               =TRUE,那么只有等lphEvents數(shù)組內(nèi)包含的所有事件對(duì)象都處于有信號(hào)狀態(tài),函數(shù)才會(huì)返回;

               =FALSE,任一個(gè)事件對(duì)象進(jìn)入有信號(hào)時(shí),函數(shù)就會(huì)返回。

             dwTimeout參數(shù)規(guī)定了 WSAWaitForMultipleEvents最多可等待一個(gè)網(wǎng)絡(luò)事件發(fā)生有多長(zhǎng)時(shí)間。超過(guò)規(guī)定的時(shí)間,函數(shù)就會(huì)立即返回。并返回WSA_WAIT_TIMEOUT。如dwsTimeout設(shè)為WSA_INFIN ITE(永遠(yuǎn)等待),那么根據(jù)fWaiiAll或等待一個(gè)網(wǎng)絡(luò)事件或所有網(wǎng)絡(luò)事件都傳信號(hào)后,才能從該函數(shù)退出。
             fAlertable,缺省設(shè)為FALSE。主要用于在重疊式I/O模型中.

              當(dāng)設(shè)置fWaiAll=false,WaitForMultipleObject再有網(wǎng)絡(luò)事件時(shí),會(huì)返回一個(gè)值,指出造成函數(shù)返回的事件對(duì)象。根據(jù)WSAWaitForMultipleEvents的返回值,減去預(yù)定義值WSA_WAIT_EVENT_0,得到具體的引用值(即索引位置),程序便可用事件數(shù)組中已發(fā)信號(hào)的事件,檢索與那個(gè)事件對(duì)應(yīng)的套接字,知道了造成網(wǎng)絡(luò)事件的套接字后,調(diào)用 WSAEnumNetworkEvents函數(shù),調(diào)查發(fā)生了什么類型的網(wǎng)絡(luò)事件。該函數(shù)定義如下:
            int WSAEnumNetworkEvents (
              SOCKET s,                                      //檢索該套接字
              WSAEVENT hEventObject,             
              LPWSANETWORKEVENTS lpNetworkEvents 
            );
                hEventObject參數(shù)則是可選的;它指定了一個(gè)事件句柄,對(duì)應(yīng)于打算重設(shè)的那個(gè)事件對(duì)象。由于我們的事件對(duì)象處在一個(gè)有信號(hào)狀態(tài),所以可將它傳入,令其自動(dòng)成為無(wú)信號(hào)狀態(tài)。
                也可以采用使用 WSAResetEvent 函數(shù)復(fù)位事件信號(hào)。
               lpNetworkEvents,就是返回的結(jié)果信息,它是一個(gè)指向WSANETWORKEVENTS結(jié)構(gòu)的指針,用于接收套接字上發(fā)生的網(wǎng)絡(luò)事件類型以及可能出現(xiàn)的任何錯(cuò)誤代碼。

            其WSANETWORKEVENTS結(jié)構(gòu)的定義:
            typedef struct _WSANETWORKEVENTS
            {
                 long lNetworkEvents;
                 int iErrorCode[FD_MAX_EVENTS];
            } WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
            lNetworkEvents參數(shù)指定了一個(gè)值,對(duì)應(yīng)于套接字上發(fā)生的所有網(wǎng)絡(luò)事件類型。
                  注意一個(gè)事件進(jìn)入置1(有信號(hào))狀態(tài)時(shí),可能會(huì)同時(shí)發(fā)生多個(gè)網(wǎng)絡(luò)事件類型。如,一個(gè)忙的服務(wù)器可能同時(shí)收到FD_READ和FD_WRITE通知。 iErrorCode參數(shù)指定的是一個(gè)錯(cuò)誤代碼數(shù)組,同lNetworkEvents中的事件關(guān)聯(lián)在一起。針對(duì)每個(gè)網(wǎng)絡(luò)事件類型,都存在著一個(gè)特殊的事件索引,名字與事件類型的名字類似,只是要在事件名字后面添加一個(gè)“ _BIT”后綴字串即可。如,對(duì)FD_READ事件類型來(lái)說(shuō),iErrorCode數(shù)組的索引標(biāo)識(shí)符便是FD_READ_BIT。

            posted on 2007-12-27 18:01 kenlistian 閱讀(6646) 評(píng)論(1)  編輯 收藏 引用

            評(píng)論

            # re: socket異步筆記 2008-09-04 10:21 david.hu
            很不錯(cuò).寫的很清楚
            "FD_READ 期望在套接字上收到數(shù)據(jù)(即讀準(zhǔn)備好)時(shí)接到通知 "~~

            比msdn 都清楚  回復(fù)  更多評(píng)論
              


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            狠狠色婷婷久久综合频道日韩| 99国产欧美精品久久久蜜芽| 久久亚洲熟女cc98cm| 狠狠久久综合伊人不卡| 人妻无码久久一区二区三区免费| 精品国产一区二区三区久久久狼 | 亚洲级αV无码毛片久久精品| 久久婷婷国产综合精品 | 日本强好片久久久久久AAA | 日日狠狠久久偷偷色综合96蜜桃| 久久精品国产AV一区二区三区 | 伊人久久大香线焦综合四虎| 久久综合精品国产一区二区三区| 午夜欧美精品久久久久久久 | 97精品久久天干天天天按摩| 久久人人超碰精品CAOPOREN| 久久久久久亚洲Av无码精品专口| 青草影院天堂男人久久| 欧美午夜精品久久久久免费视| 久久天天躁狠狠躁夜夜2020| 国内精品久久久久伊人av| 久久99九九国产免费看小说| 久久av免费天堂小草播放| 久久精品国产精品国产精品污| 久久婷婷五月综合97色一本一本| 久久这里都是精品| 久久www免费人成看国产片| 国产精品久久一区二区三区| 亚洲av日韩精品久久久久久a | 91精品国产91久久久久久青草 | 国产精品99久久久久久猫咪 | 国产精品99久久精品爆乳| 久久se精品一区二区| 高清免费久久午夜精品| 久久婷婷五月综合97色一本一本 | 国产精品美女久久久久| 天天爽天天狠久久久综合麻豆| 2020国产成人久久精品| 欧美精品九九99久久在观看| 久久久久国产成人精品亚洲午夜| 99精品久久久久久久婷婷|