• <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
            摘自《Visual C++網絡游戲建模與實現》(蘇羽、王媛媛編著) 
            Win32重疊I/O(Overloapped I/O)機制允許發起一個操作,然后在操作完成之后接受
            到信息。對于那種需要很長時間才能完成的操作來說,重疊I/O機制尤其有用,因為發起
            重疊操作的線程在重疊請求發出后就可以自由地做別的事情了。
                在Windows NT/2000上,提供真正可擴展的I/O模型就是使用完成端口(Completion
            Port)的重疊I/O。
                ……
                可以把完成端口看成系統維護的一個隊列,操作系統把重疊I/O操作完成的事件通知
            放到該隊列里,由于是暴露“操作完成”的事件通知,所以命名為“完成端口”(Completion
            Ports)。一個Socket被創建后,可以在任何時刻和一個完成端口聯系起來。
                一般來說,一個應用程序可以創建多個工作線程來處理完成端口上的通知事件。工作
            線程的數量依賴于程序的具體需要。但是在理想的情況下,應該對應一個CPU創建一個線
            程。因為在完成端口理想模型中,每個線程都可以從系統獲得一個“原子”性的時間片,輪
            番運行并檢查完成端口,線程的切換是額外的開銷。在實際開發的時候,還要考慮這些線
            程是否牽涉到其他堵塞操作的情況。如果某線程進行堵塞操作,系統則將其掛起,讓別的
            線程獲得運行時間。因此,如果有這樣的情況,可以多創建幾個線程來盡量利用時間。
                應用完成端口分兩步走:
                1. 創建完成端口句柄:
                HANDLE hIocp;
                hIocp=CreateIoCompletionPort(
                INVALID_HANDLE_VALUE,
                NULL,
                (ULONG_PTR)0,
                0);
                if(hIocp==NULL) {
                //如果錯誤
                  ……
                }
                注意在第1個參數(FileHandle)傳入INVALID_FILE_HANDLE,第2個參數(ExistingCompletionPort)
            傳入NULL,系統將創建一個新的完成端口句柄,沒有任何I/O句柄與其關聯。

                2. 完成端口創建成功后,在Socket和完成端口之間建立關聯。再次調用CreateIoCompletionPort
            函數,這一次在第1個參數FileHandle傳入創建的Socket句柄,參數ExistingCompletionPort
            為已經創建的完成端口句柄。
                以下代碼創建了一個Socket并把它和完成端口聯系起來。
                SOCKET s;
                s=Socket(AF_INET,SOCK_STREAM,0);
                if(s==INVALID_SOCKET) {
                if(CreateIoCompletionPort((HANDLE)s,
                hIocp,
                (ULONG_PTR)0,
                0)==NULL)
                {
                //如果創建失敗
                  ……
                }
                }
                到此為止,Socket已經成功和完成端口相關聯。在此Socket進行的重疊I/O操作結果均
            使用完成端口發出通知。

                注意:CreateIoCompletionPort函數的第3個參數允許開發人員傳入一個類型為ULONG_PTR
            的數據成員,我們把它稱為完成鍵(Completion Key),此數據成員可以設計為指向包含Socket
            信息的一個結構體的一個指針,用來把相關的環境信息和Socket聯系起來,每次完成通知來
            到的同時,該環境信息也隨著通知一起返回給開發人員。

                完成端口創建以及與Socket關聯之后,就要創建一個或多個工作線程來處理完成通知,
            每個線程都可以循環地調用GetQueuedCompletionStatus函數,檢查完成端口上的通知事件。
                在舉例說明一個典型的工作線程之前,我們先討論一下重疊I/O的過程。到一個重疊I/O
            被發起,一個Overlapped結構體的指針就要作為參數傳遞給系統。當操作完成時,
            GetQueueCompletionStatus就可以返回指向同一個Overlapped結構的指針。為了辨認和定位
            這個已完成的操作,開發人員最好定義自己的OVERLAPPED結構,以包含一些自己定義的關于
            操作本身的額外信息。比如:
                typedef struct _OVERLAPPELUS {
                  OVERLAPPED ol;
                  SOCKET s, sclient;
                  int OpCode;
                  WSABUF wbuf;
                  DWORD dwBytes, dwFlags;
                } OVERLAPPELUS;
                此結構的第1個成員為默認的OVERLAPPED結構,第2和第3個為本地服務Socket和與該
            操作相關的客戶socket,第4個成員為操作類型,對于Socket,現在定義的有以下3種:
                #define OP_READ 0
                #define OP_WRITE 1
                #define OP_ACCEPT 2
                然后還有應用程序的Socket緩沖區,操作數據量,標志位以及其他開發人員認為有用
            的信息。
                當進行重疊I/O操作,把OVERLAPPELUS結構作為重疊I/O的參數lpOverlapp傳遞(如
            WSASend,WASRecv,等函數的lpOverlapped參數,要求傳入一個OVERLAPP結構的指針)。
                當操作完成后,GetQueuedCompletionStatus函數返回一個LPOVERLAPPED類型的指針,
            這個指針其實是指向開發人員定義的擴展OVERLAPPELUS結構,包含著開發人員早先傳入的
            全部信息。

                注意:OVERLAPPED成員不一定要求是OVERLAPPELUS擴展結構的一個成員,在獲得
            OVERLAPPED指針之后,可以用CONTAINING_RECORD宏獲得相應的擴展結構的指針。

                典型的Worker Thread結構:
                DWORD WINAPI WorkerThread(LPVOID lpParam)
                {
                  ULONG_PTR *PerHandleKey;
                  OVERLAPPED *Overlap;
                  OVERLAPPELUS *OverlapPlus, *newolp;
                  DWORD dwBytesXfered;
                 
                  while(1)
                  {
                    ret=GetQueuedCompletionStatus(
                    hIocp,
                    &dwBytesXfered,
                    (PULONG_PTR)&PerHandleKey,
                    &Overlap,
                    INFINITE);
                    if(ret==0)
                    {
                      //如果操作失敗
                      continue;
                    }
                   
                    OverlapPlus=CONTATING_RECORD(Overlap, OVERLAPPELUS, ol);
                    switch(OverlapPlus->OpCode)
                    {
                      case OP_ACCEPT:
                        CreateIoCompletionPort(
                            (HANDLE)OverlapPlus->sclient,
                            hIocp,
                            (ULONG_PTR)0,
                            0);
                        newolp=AllocateOverlappelus();
                        newolp->s=OverlapPlus->sclient;
                        newolp->OpCode=OP_READ;
                        PrepareSendBuffer(&newolp->wbuf);
                        ret=WSASend(
                          newolp->s,
                          &newolp->wbuf,
                          1,
                          &newolp->dwBytes,
                          0,
                          &newolp.ol,
                          NULL);
                        if(ret==SOCKET_ERROR)
                        {
                          if(WSAGetLastError()!=WSA_IO_PENDING)
                          {
                            //進行錯誤處理
                            ……
                          }
                        }
                        FreeOverlappelus(OverlapPlus);
                        SetEvent(hAcceptThread);
                        break;
                      case OP_READ:
                        memset(&OverlapPlus->ol,0,sizeof(OVERLAPPED));
                        ret=WSARecv(
                            OverlapPlus->s,
                            &OverlapPlus->wbuf,
                            1,
                            &OverlapPlus->dwBytes,
                            &OverlapPlus->dwFlags,
                            &OverlapPlus->ol,
                            NULL);
                        if(ret==SOCKET_ERROR)
                        {
                          if(WSAGetLastError()!=WSA_IO_PENDING)
                          {
                            //錯誤處理
                            ……
                          }
                        }
                        break;
                      case OP_WRITE:
                        break;
                    }/*switch結束*/
                  }/*while結束*/
                }/*WorkerThread結束*/
               
                注意:如果Overlapped操作立刻失敗(比如,返回SOCKET_ERROR或其他非
                WSA_IO_PENDING的錯誤),則沒有任何完成通知事件會被放到完成端口隊列里。反之,
                則一定有相應的通知事件被放到端口隊列。

            posted on 2007-04-28 17:14 jay 閱讀(662) 評論(0)  編輯 收藏 引用 所屬分類: socket
            国产成人久久AV免费| 久久无码中文字幕东京热| 精品熟女少妇AV免费久久| 久久久久国产一区二区三区| 久久精品天天中文字幕人妻| 欧美喷潮久久久XXXXx| 久久无码高潮喷水| 久久久久高潮综合影院| 亚洲中文字幕无码久久精品1| 国内精品久久久久影院薰衣草| 女人高潮久久久叫人喷水| 久久久久免费精品国产| 久久国产亚洲精品| 欧美丰满熟妇BBB久久久| 久久久久久亚洲Av无码精品专口| 久久精品国产亚洲AV无码麻豆 | 久久99精品国产| 精品999久久久久久中文字幕| 99久久超碰中文字幕伊人| 国产精品成人无码久久久久久| 99久久成人18免费网站| 亚洲色欲久久久久综合网| 一本色道久久88精品综合| 无码超乳爆乳中文字幕久久 | 久久久久亚洲av毛片大| 久久久久久国产a免费观看黄色大片 | 久久精品一区二区国产| 精品久久久久中文字| 久久久久久亚洲精品影院| 丰满少妇高潮惨叫久久久| 久久国产福利免费| 久久久婷婷五月亚洲97号色 | 久久久久久国产精品免费无码 | 精品国产91久久久久久久a| 久久久久久国产精品无码下载 | 久久国产精品免费| 久久精品国产亚洲AV无码娇色 | 久久久久高潮综合影院| 久久久国产精品网站| 中文精品久久久久人妻不卡| 国产午夜电影久久|