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

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

                             // 為本次客戶請求產生子線程
                             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結構的指針
                                  1,                                                 // WSABUF數組的個數
                                  &dwNumOfBytesRecved,      // 存放當WSARecv完成后所接收到的字節數
                                  &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,       // 當一個同步I/O完成后,接收到的字節數
                                   TRUE,                      // 等待I/O操作的完成
                                   &dwFlags                   
                             );
                            if   (bResult  ==  FALSE  &&  WSAGetLastError()  !=  WSA_IO_INCOMPLETE)
                           {
                                     printf("WSAGetOverlappdResult(..) failed.\n");
                                     free(lpPerHandleData);
                                     return 1;   // 錯誤退出
                            }
                    
                            if  (dwBytesTransferred == 0)
                            {
                                       printf("客戶端已退出,將斷開與之的連接!\n");
                                       closesocket(lpPerHandleData->hSocket);
                                       free(lpPerHandleData);
                                       break;
                            }

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

                           // 發送另外一個請求操作
                           ZeroMemory(&Overlapped, sizeof(WSAOVERLAPPED));
                           lpPerHandleData->nOperateType = POST_RECV;

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

                     }

                     return 0;
            }
                     程序結構比較清晰,lpPerHandleData是主線程與子線程聯系的紐帶,子線程是通過這個結構獲得所處理客戶端的情況的。在不同的應用中可以將這個結構定義成不同的形式,以符合所實現應用的需要。注意結構體的nOperateType在GetOverlappedResult返回時用到,可以根據這個字段確定我們下一步的操作。請朋友們多提意見了。

            posted on 2007-04-10 18:06 jay 閱讀(3141) 評論(0)  編輯 收藏 引用 所屬分類: socket
            亚洲午夜精品久久久久久人妖| 久久噜噜久久久精品66| 久久996热精品xxxx| 久久中文字幕一区二区| 亚洲天堂久久精品| 人妻无码久久精品| 久久精品国产99久久久| 人妻精品久久无码专区精东影业 | 亚洲精品无码久久一线| 中文字幕精品无码久久久久久3D日动漫 | 久久久久久精品久久久久| 久久91精品国产91久| 香蕉久久av一区二区三区| 久久精品国产亚洲AV无码娇色| 久久人人爽人人爽人人片AV东京热| 欧美国产成人久久精品| 伊人久久大香线蕉成人| 色偷偷偷久久伊人大杳蕉| 久久久久久免费一区二区三区| 久久香蕉综合色一综合色88| 韩国免费A级毛片久久| 国产精品久久一区二区三区| 久久久久亚洲AV成人网人人网站| 久久久亚洲欧洲日产国码二区| 久久99精品国产麻豆宅宅| 亚洲午夜久久久久妓女影院 | 久久久中文字幕日本| yellow中文字幕久久网| 性欧美丰满熟妇XXXX性久久久 | 久久免费的精品国产V∧| 久久婷婷国产综合精品| 国产精品久久久亚洲| 99久久人妻无码精品系列| AAA级久久久精品无码区| 久久综合狠狠综合久久97色| 久久久久久久尹人综合网亚洲| 伊人久久大香线蕉精品| 亚洲精品成人网久久久久久| 九九热久久免费视频| 久久AV无码精品人妻糸列| 久久亚洲中文字幕精品有坂深雪|