• <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>

            yehao's Blog

            理解完成端口(IO completion port)

            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/kevinlynx/archive/2008/01/27/2068739.aspx


              關于完成端口網上有很多文章,不過我個人覺得大多都講得不夠清楚。給的例子要不就是給一個復雜的封裝,要不就是給一個簡單的收發數據。注意,完成端口不僅僅用于網絡數據的收發,它可以用于windows 平臺的各種IO操作。不過我這里只關注在winsock編程中的應用。

                要寫出一篇真的讓人能夠明白的文章,不那么容易。這里我只暫時貼些我的理解。遲些時候如果有空的話,我倒有興趣寫個詳細的入門文章。

            1.26.2008

            Kevin Lynx

             
            理解完成端口:
             
                   就目前所了解的信息來說,完成端口通常都會與重疊IO有關聯。完成端口可被看作是一個隊列。各種操作都會被放到該隊列里,程序在遲些時候查詢此隊列獲取之前提交的IO操作結果。

                   注意,無論是重疊IO還是完成端口,都不僅僅用于socket的操作,他們是用于各種IO的操作。


            IOCP不是為每一個客戶端連接建立一個線程。

            要區分IOCP和事件通知模型的區別,事件通知模型是先得到事件,然后根據事件類型去獲取或者發送數據;而IOCP則是先提交動作(發送或接收),后得到通知,當得到通知時,通常就意味著之前提交的動作已經完成了。

             
            When you use IOCP, you spawn a pool of threads once - and they are used to handle the network I/O in your application. Technically, in Windows 2000, you don't even have to spawn the pool yourself - you can let Windows take care of the spawning and management of the threads in the pool。

            IOCP其實也屬于一種同步對象,就像Windows里的Event對象一樣。IOCP用于同步IO操作。在異步IO操作中,提交了一個異步操作后,某些時候就需要得知操作的結果,也就是同步一下。

             
            http://www.codeproject.com/KB/IP/iocp_server_client.aspx
            A server application is fairly meaningless if it cannot service multiple clients at the same time, usually asynchronous I/O calls and multithreading is used for this purpose. By definition, an asynchronous I/O call returns immediately, leaving the I/O call pending. At some point of time, the result of the I/O asynchronous call must be synchronized with the main thread. This can be done in different ways. The synchronization can be performed by:
            •Using events - A signal is set as soon as the asynchronous call is finished. The disadvantage of this approach is that the thread has to check or wait for the event to be set. •Using the GetOverlappedResult function - This approach has the same disadvantage as the approach above. •Using Asynchronous Procedure Calls (or APC) - There are several disadvantages associated with this approach. First, the APC is always called in the context of the calling thread, and second, in order to be able to execute the APCs, the calling thread has to be suspended in the so called alterable wait state. •Using IOCP - The disadvantage of this approach is that there are many practical thorny programming problems that must be solved. Coding IOCP can be a bit of a hassle. 
            這里我要特別強調一下異步IO和非阻塞IO的區別,異步IO就是把IO提交給系統,讓系統替你做,做完了再用某種方式通知你;非阻塞IO就是你要通過某種方式不定時地向系統詢問你是否可以開始做某個IO,當可以開始后,還是要自己來完成IO。
             
                   不可以通過接受數據是否為0來判斷客戶端是否斷開,只有當調用closesocket時才可以通過這個方法判斷,如果是意外退出(斷電,網絡故障),則判斷不出。這個時候可以采用定時發送數據(心跳信息)來確認。

             
                   創建IOCP程序,一般的步驟:

            1.       創建一個單句柄數據結構體,該結構體里一般都包含一個套接字數據。因為IOCP實際上會有固定的幾個線程(工作線程),這些線程在IOCP結果隊列里查詢IO操作結果。這些結果不止是在一個套接字上進行的操作(讀或寫),而是包括了所有與該IOCP對象關聯起來的套接字上的操作結果。因此,為了區分某次操作結果屬于哪個套接字,就需要這個單句柄數據結構里包含這個套接字句柄。

            2.       創建一個以OVERLAPPED為首個元素的數據結構體。該結構體實際上對應著一個IO操作(例如WSASend)。對于 WSASend, WSARecv以及查詢操作結果函數都需要一個OVERLAPPED參數(一般是指針),通常情況下我們需要更多的數據,因此定義的這個結構體里通常包含了更多的數據(例如WSABUF,它可以用來容納WSARecv接受到的數據)。之所以要把OVERLAPPED 作為這個結構體的第一個元素,是為了在使用查詢函數GetQueuedCompletionStatus后,可以通過該函數返回的OVERLAPPED類型的指針得到我們這里定義的結構體對象地址,從而獲取更多的數據。

            3.       每一次接受到新的連接時(accept),都將這個新的套接字與完成端口相關聯。并且創建一個單句柄對象(也就是完成鍵)。每一個套接字都有一個關聯的單句柄對象。而每一個IO操作都有一個關聯的OVERLAPPED相關的數據結構(上一步定義的結構體)。

            4.       可以在任何時候提交異步IO請求,例如WSASend, WSARecv。這里需要為OVERLAPPED相關的結構體指定操作類型。一個典型的結構體為(即第二步定義的結構體):

                          struct IOContext
            {
                          /// 很多函數需要此參數
                          OVERLAPPED ol;
                          /// 存放接受數據
                          char buf[MAX_BUF];
                          ///
                          WSABUF wsabuf;
                          /// 操作類型,提交IO操作時指定該值,在查詢操作結果時,可以重新獲取到該值
                          int op_type;
            };
            在創建該結構體的變量時,為op_type指定一個值。然后將此結構體的地址給WSASend之類的函數。在工作者線程中執行查詢時,實際上得到了該結構體的地址(結構體變量),那么,就可以獲取op_type的值。
            注意:查詢結構只能獲取IO操作的字節數(以及IO操作結果數據),不能知道IO操作的類型。所以IO操作的類型實際上是在這里用戶自己指定的。
            當執行WSASend時,設置op_type為SEND(自己定義的常量),執行WSARecv時,指定READ。然后在查詢結果時,可以根據op_type知道這個操作結果是什么類型。如果是SEND,那么就表示之前提交的WSASend操作。
            IOCP是一個異步操作機制,之所以是異步,就是因為可以隨時提交IO操作。提交之后具體的操作由系統為你完成。完成后就需要某種機制來得知操作結果。IOCP設置的這個結果隊列就是一種機制。
             
                  
             
            5.       可以通過PostQueuedCompletionStatus手動地往結果隊列里放置一個操作結果。通常這個函數都用于讓工作者線程退出。例如:

                               PostQueuedCompletionStatus( cp_handle, 0, NULL, NULL );
            然后在工作者線程里:

                     ret = GetQueuedCompletionStatus( cp_handle, &transfer_bytes, (PULONG_PTR) &hc,
                          (LPOVERLAPPED*)&ic, INFINITE );
                     if( ic == NULL )
                     {
                          printf( "ic == NULL\n" );
                          /*
                               使用PostQueuedCompletionStatus傳遞過來的數據,
                               這里約定ic==NULL時退出
                          */
                          break;
                     }
                    
            6.     如果不提交任何IO操作,那么結果隊列里很有可能一直都是空的。那么GetQueued這個查詢函數就會一直得不到數據。
             
            7.     縱觀IOCP程序,一個比較復雜的地方在于資源的釋放。在接收到一個新的連接時,會為這個連接創建單句柄數據,執行IO操作的話,還要創建OVERLAPPED相關結構體變量。這些變量的地址都會在工作者線程中通過GetQueued..函數獲取,并在工作者線程中使用。一個比較直接的做法是在工作者線程中釋放這些資源。
             
             
             
            推薦些文章:

            幾種socket模型的代碼:http://blog.csdn.net/mlite/archive/2006/04/30/699340.aspx
                              又一個簡單的IOCP代碼:http://www.go321.cn/html/app/cpp/20070526/30207.html
                              另一個例子,那幅圖有點意義:http://www.3800hk.com/Article/cxsj/vc/wllbcvc/2005-08-25/Article_54111.html
                              codeproject上的文章:http://www.codeproject.com/KB/IP/iocp_server_client.aspx
                              codeproject上的另一篇:http://www.codeproject.com/KB/IP/jbsocketserver1.aspx
                              MSDN上的,前部分由點意義:http://msdn.microsoft.com/msdnmag/issues/1000/winsock/
                            
                             其實完成端口的例子在細節上有很多方法,例如accept, AcceptEx之類,對于accept的處理尤其多。這些無疑又給初學者帶來了迷惑。我覺得只要把握住幾個要點就行了:異步操作,結果隊列,數據的傳送(提交操作時傳進去,查詢時取出來),工作者線程

            posted on 2011-04-24 18:59 厚積薄發 閱讀(3057) 評論(0)  編輯 收藏 引用 所屬分類: 網絡編程

            導航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            常用鏈接

            留言簿

            隨筆分類

            文章分類

            文章檔案

            搜索

            最新評論

            亚洲AV无码一区东京热久久| 久久久久中文字幕| 亚洲人成无码久久电影网站| 伊人久久一区二区三区无码| 亚洲熟妇无码另类久久久| 久久97精品久久久久久久不卡| 国产AV影片久久久久久| 久久WWW免费人成一看片| 久久青草国产精品一区| 久久婷婷人人澡人人爽人人爱| 精品精品国产自在久久高清| 香蕉aa三级久久毛片| 1000部精品久久久久久久久| 怡红院日本一道日本久久 | 国产激情久久久久影院老熟女| 青草久久久国产线免观| 精品久久久久久综合日本| 2021国内精品久久久久久影院| 97久久精品国产精品青草| 国产精品中文久久久久久久| 青青青国产精品国产精品久久久久| 久久久久久久综合狠狠综合| 999久久久国产精品| 久久99精品久久只有精品| 99久久精品国产一区二区 | 麻豆亚洲AV永久无码精品久久| 久久精品中文字幕一区| 久久精品国产精品亚洲精品| 97久久久精品综合88久久| 无码国内精品久久人妻| 久久久久人妻一区二区三区| 亚洲欧美国产日韩综合久久| 久久国产高清一区二区三区| 亚洲国产精品一区二区久久| 99国产精品久久| 99久久99久久久精品齐齐| 99久久精品毛片免费播放| 国产精品久久99| 九九99精品久久久久久| 国产真实乱对白精彩久久| 国产成人精品综合久久久|