• <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>
            隨筆-250  評(píng)論-20  文章-55  trackbacks-0
             重疊I/O也是一種異步I/O,同樣也支持Win32的其它對(duì)象,當(dāng)然在Winsock中可以發(fā)揮很大的作用。使用Overlapped開發(fā)支持一定數(shù)量的Socket的應(yīng)用,效率是相當(dāng)很高的。但就我個(gè)人的觀點(diǎn),在Win32下做網(wǎng)絡(luò)應(yīng)用的開發(fā),如果要支持100個(gè)以上的Socket的話,還是考慮Completion Port I/O。要求支持Socket最好是100個(gè)以下,我是基于這樣考慮的:Overlapped是通過多線程支持多Socket的,如果開辟的線程太多的話,勢必影響了系統(tǒng)的性能;Completion Port I/O可以更好支持大量的客戶端。這兩種在Windows下具有高效率的I/O都不支持Windows CE及其它平臺(tái)。我在這里說一下在開發(fā)網(wǎng)絡(luò)應(yīng)用時(shí)什么時(shí)候用Overlapped I/O 模型:準(zhǔn)備在Win98和以上版本或WinNT3.1和以上版本做開發(fā),且要求支持Socket最好在100個(gè)以下。另外在串口開發(fā)中,考慮效率問題,有很多地方用到了Overlapped I/O。
                     Overlapped I/O主要涉及一個(gè)數(shù)據(jù)結(jié)構(gòu)Overlapped(Winsock中是WSAOverlapped)和一個(gè)函數(shù)WSAGetOverlappedResult(..)。
                     Overlapped I/O執(zhí)行步驟很清晰,只要下面三步:
                     (1) 應(yīng)用先通過WSASend或WSARecv(不知道有沒有其它的請(qǐng)求,我只用過這兩個(gè)函數(shù)),注意要向兩者轉(zhuǎn)入WSAOverlapped參數(shù),
            表示,執(zhí)行的是Overlapped操作;
                     (2)在一個(gè)循環(huán)中,調(diào)用GetOverlappedResult(..)等待操作完成,GetOverlappedResult返回時(shí),進(jìn)行相應(yīng)的處理,如處理數(shù)據(jù);
                     (3) 最后,還在(2)循環(huán)中,發(fā)送另外一個(gè)請(qǐng)求(WSASend或WSARecv),重復(fù)處理(2)、(3)兩步。
                    第一步中執(zhí)行WSASend或WSARecv時(shí),函數(shù)立即返回,得到SOCKET_ERROR信息且此時(shí)WSAGetErrorLast返回WSA_IO_PENDING,說明調(diào)用已成功,Winsock正在處理WSASend或WSARecv的請(qǐng)求。個(gè)人認(rèn)為Winsock在內(nèi)部開辟了新的線程處理,應(yīng)用程序不用管理多線程,達(dá)到異步的目的,有利于性能的提高。WSASend或WSARecv也可能返回"0",表示立即成功,這時(shí),應(yīng)用還是可以在WSAGetOverlappedResult()處等待,處理過程與上面是一樣的;也就是說我們不須要馬上在WSASend或WSARecv進(jìn)行相關(guān)的處理。
                    WSAGetOverlappedResult返回FASLE且WSAGetLastError返回WSA_IO_INCOMPLETE,表示處理正在進(jìn)行中。   

                    下面我給出支持單個(gè)Socket及支持多個(gè)Socket的Console程序代碼。先來看看支持單個(gè)Socket的程序,考慮到代碼簡潔性,只給一個(gè)框架,同時(shí)不進(jìn)行出錯(cuò)處理。
            int main()
            {
                      WSAOVERLAPPED     Overlapped;
                              
                      // 啟動(dòng)Winsock及建立監(jiān)聽套接字
                       listen(hListenSocket,  5);
                   
                       hClientSocket   =   accept(hListenSocket,   NULL,   NULL);
                       ZeroMemory(&Overlapped,   sizeof(WSAOVERLAPPED));
                       
                       nResult   =   WSARecv(...);    // 發(fā)出請(qǐng)求
                    
                      for (; ;)
                      {
                               bResult   =   WSAGetOverlappedResult(...);
                               // 函數(shù)返回后進(jìn)行相應(yīng)的處理
                               nResult   =   WSARecv(...);  // 發(fā)出另外一個(gè)請(qǐng)求
                      }
            }
                    上面的程序只是想說明一下過程,程序沒有實(shí)現(xiàn)什么功能。這樣做的目的是節(jié)約字?jǐn)?shù),用來說明我下面支持多個(gè)Socket的Console應(yīng)用。請(qǐng)繼續(xù)看。
                    先看一個(gè)自定義的結(jié)構(gòu)體,單句柄數(shù)據(jù)結(jié)構(gòu),通過該結(jié)構(gòu),主線程與某個(gè)特定的子線程中的套接字相互聯(lián)系。
                     typedef   struct    _PER_HANDLE_DATA
                     {
                               SOCKET   hSocket;     // 主鍵:通信套接字
                              char    szClientIP[16];// 自定義字段:客戶端地址
                              int nOperateType;   // 自定義字段:操作類型
                      }PER_HANDLE_DATA,   FAR*  LPPER_HANDLE_DATA;
                     在上面的結(jié)構(gòu)中還可以加入自己需要的字段。在我下面的例子程序中,szClientIP是用來保存連接上來的客戶端的IP的,這樣在主線程將這個(gè)結(jié)構(gòu)體傳給子線程后,在子線程中根據(jù)客戶端IP就知道目前處理的是哪個(gè)客戶端了。下面是程序的大部分,同樣除去一些簡單的出錯(cuò)輸出。
            #define     LISTEN_PORT 5000
            #define     DATA_BUFSIZE 8192
            #define     POST_RECV 0X01   
            #define     POST_SEND 0X02

            int   main(  )
            {
                       LPPER_HANDLE_DATA    lpPerHandleData;
                       SOCKET               hListenSocket;
                       SOCKET               hClientSocket;
                       SOCKADDR_IN          ClientAddr;
                       int                  nAddrLen;
                       HANDLE               hThread; 

                      // Start WinSock and create a listen socket.

                      listen(hListenSocket,  5); 
                      for (; ;)
                     {
                              nAddrLen  =  sizeof(SOCKADDR);
                              hClientSocket  =  accept(hListenSocket,  (LPSOCKADDR)&ClientAddr,  &nAddrLen);

                              lpPerHandleData = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
                              lpPerHandleData->hSocket  =  hClientSocket;
                              // 注意這里將連接的客戶端的IP地址,保存到了lpPerHandleData字段中了
                             strcpy(lpPerHandleData->szClientIP,   inet_ntoa(ClientAddr.sin_addr));

                             // 為本次客戶請(qǐng)求產(chǎn)生子線程
                             hThread = CreateThread(
                                       NULL,
                                       0,
                                       OverlappedThread,
                                       lpPerHandleData,   // 將lpPerHandleData傳給子線程
                                       0,
                                       NULL
                              );
                             CloseHandle(hThread);
                     }   
             return 0;
            }

            DWORD   WINAPI   OverlappedThread(LPVOID    lpParam)
            {
                        LPPER_HANDLE_DATA     lpPerHandleData   =   (LPPER_HANDLE_DATA)lpParam;
                        WSAOVERLAPPED Overlapped;
                        WSABUF        wsaBuf;
                        char          Buffer[DATA_BUFSIZE];
                        BOOL          bResult;
                        int           nResult;
               
                        ZeroMemory(&Overlapped, sizeof(WSAOVERLAPPED));
                        wsaBuf.buf = Buffer;
                        wsaBuf.len = sizeof(Buffer);
                        lpPerHandleData->nOperateType = POST_RECV;     // 記錄本次操作是Recv(..)

                        dwFlags = 0;
                        nResult = WSARecv(
                                  lpPerHandleData->hSocket,   // Receive socket
                                  &wsaBuf,                                  // 指向WSABUF結(jié)構(gòu)的指針
                                  1,                                                 // WSABUF數(shù)組的個(gè)數(shù)
                                  &dwNumOfBytesRecved,      // 存放當(dāng)WSARecv完成后所接收到的字節(jié)數(shù)
                                  &dwFlags,                                 // A pointer to flags
                                  &Overlapped,                           // A pointer to a WSAOVERLAPPED structure
                                  NULL                                         // A pointer to the completion routine,this is NULL
                       );
                      if   ( nResult   ==   SOCKET_ERROR     &&   GetLastError() !=       WSA_IO_PENDING)
                      {
                             printf("WSARecv(..) failed.\n");
                             free(lpPerHandleData);
                             return 1;
                      }

                     while (TRUE)
                     {
                             bResult  =  WSAGetOverlappedResult(
                                    lpPerHandleData->hSocket,  
                                    &Overlapped,           
                                    &dwBytesTransferred,       // 當(dāng)一個(gè)同步I/O完成后,接收到的字節(jié)數(shù)
                                   TRUE,                      // 等待I/O操作的完成
                                   &dwFlags                   
                             );
                            if   (bResult  ==  FALSE  &&  WSAGetLastError()  !=  WSA_IO_INCOMPLETE)
                           {
                                     printf("WSAGetOverlappdResult(..) failed.\n");
                                     free(lpPerHandleData);
                                     return 1;   // 錯(cuò)誤退出
                            }
                    
                            if  (dwBytesTransferred == 0)
                            {
                                       printf("客戶端已退出,將斷開與之的連接!\n");
                                       closesocket(lpPerHandleData->hSocket);
                                       free(lpPerHandleData);
                                       break;
                            }

                             // 在這里將接收到的數(shù)據(jù)進(jìn)行處理
                           printf("Received from IP: %s.\ndata: %s\n", lpPerHandleData->szClientIP, wsaBuf.buf);    

                           // 發(fā)送另外一個(gè)請(qǐng)求操作
                           ZeroMemory(&Overlapped, sizeof(WSAOVERLAPPED));
                           lpPerHandleData->nOperateType = POST_RECV;

                           dwFlags = 0;
                            nResult = WSARecv(...);
                            if (...)
            {}

                     }

                     return 0;
            }
                     程序結(jié)構(gòu)比較清晰,lpPerHandleData是主線程與子線程聯(lián)系的紐帶,子線程是通過這個(gè)結(jié)構(gòu)獲得所處理客戶端的情況的。在不同的應(yīng)用中可以將這個(gè)結(jié)構(gòu)定義成不同的形式,以符合所實(shí)現(xiàn)應(yīng)用的需要。注意結(jié)構(gòu)體的nOperateType在GetOverlappedResult返回時(shí)用到,可以根據(jù)這個(gè)字段確定我們下一步的操作。請(qǐng)朋友們多提意見了。

            posted on 2007-04-10 18:06 jay 閱讀(3140) 評(píng)論(0)  編輯 收藏 引用 所屬分類: socket
            精品国产乱码久久久久软件| 国产巨作麻豆欧美亚洲综合久久| 国产高潮久久免费观看| 看久久久久久a级毛片| 精品综合久久久久久98| 狠狠色丁香久久婷婷综合图片 | 久久99精品免费一区二区| 久久精品视频免费| 2021国产成人精品久久| 亚洲综合精品香蕉久久网97| 久久w5ww成w人免费| 99久久婷婷国产综合亚洲| 99精品久久久久中文字幕| 欧洲成人午夜精品无码区久久| 精品国产日韩久久亚洲| 无码精品久久久天天影视| 少妇高潮惨叫久久久久久 | 久久婷婷是五月综合色狠狠| 日日狠狠久久偷偷色综合免费 | 久久青青草原精品国产| 久久人人爽人人爽人人片AV不| 91久久婷婷国产综合精品青草| 久久免费精品视频| segui久久国产精品| 一本一道久久a久久精品综合| 久久精品国产久精国产果冻传媒| 无码人妻少妇久久中文字幕蜜桃| …久久精品99久久香蕉国产| 久久99精品国产麻豆婷婷| 亚洲欧美另类日本久久国产真实乱对白 | 香港aa三级久久三级老师2021国产三级精品三级在 | 亚洲精品无码久久久久sm| 久久精品蜜芽亚洲国产AV| 国产精品狼人久久久久影院| 日日狠狠久久偷偷色综合免费| 亚洲国产一成人久久精品| 国产午夜精品理论片久久影视| 欧美日韩中文字幕久久久不卡 | 亚洲国产精品高清久久久| 国产L精品国产亚洲区久久| 久久久www免费人成精品|