null__吧 关注:220贴子:4,306
  • 3回复贴,共1

winsock IO模型之五完成端口

只看楼主收藏回复

今天有些烧饼,所以见谅


IP属地:福建1楼2011-05-30 17:51回复
         CreateIoCompletionPort((HANDLE)sClient, CompletionPort, (DWORD)sClient, 0);
       
         // 为新连接开启一个异步操作
         lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
                                                           GetProcessHeap(),
                                                           HEAP_ZERO_MEMORY,
                                                           sizeof(PER_IO_OPERATION_DATA));
         lpPerIOData->Buffer.len = MSGSIZE;
         lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
         lpPerIOData->OperationType = RECV_POSTED;
         WSARecv(sClient,
                 &lpPerIOData->Buffer,
                 1,
                 &lpPerIOData->NumberOfBytesRecvd,
                 &lpPerIOData->Flags,
                 &lpPerIOData->overlap,
                 NULL);
       }
    PostQueuedCompletionStatus(CompletionPort, 0xFFFFFFFF, 0, NULL);//向每个工作者线程都发送一个特殊的完成数据包
    CloseHandle(CompletionPort);
    closesocket(sListen);
    WSACleanup();
    return 0;
    }
    DWORD WINAPI WorkerThread(LPVOID CompletionPortID)
    {
       HANDLE CompletionPort=(HANDLE)CompletionPortID;
       DWORD dwBytesTransferred;
       SOCKET sClient;
       LPPER_IO_OPERATION_DATA lpPerIOData = NULL;
       while (TRUE)
       {
         GetQueuedCompletionStatus(
                                   CompletionPort,
                                   &dwBytesTransferred,
    


    IP属地:福建3楼2011-05-30 17:52
    回复
                                     (LPDWORD)&sClient,
                                     (LPOVERLAPPED *) &lpPerIOData,
                                     INFINITE);//在完成端口上等待 I/O 请求完成的通知
           if (dwBytesTransferred == 0xFFFFFFFF)
           {
             return 0;
           }
          if (lpPerIOData->OperationType == RECV_POSTED)
          {
            if (dwBytesTransferred == 0)
            {
              // 客户端关闭
              closesocket(sClient);
              HeapFree(GetProcessHeap(), 0, lpPerIOData);
            }
            else
            {
              lpPerIOData->szMessage[dwBytesTransferred] = '\0';
              send(sClient, lpPerIOData->szMessage, dwBytesTransferred, 0);
              // 开启另一个异步操作
              memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
              lpPerIOData->Buffer.len = MSGSIZE;
              lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
              lpPerIOData->OperationType = RECV_POSTED;
              WSARecv(sClient,
                      &lpPerIOData->Buffer,
                      1,
                      &lpPerIOData->NumberOfBytesRecvd,
                      &lpPerIOData->Flags,
                      &lpPerIOData->overlap,
                      NULL);
            }
          }
         }
      return 0;
      }
      首先,说说主线程:
      1.创建完成端口对象
      2.创建工作者线程(这里工作者线程的数量是按照CPU的个数来决定的,这样可以达到最佳性能)
      3.创建监听套接字,绑定,监听,然后程序进入循环
      4.在循环中,我做了以下几件事情:
      (1).接受一个客户端连接
      (2).将该客户端套接字与完成端口绑定到一起(还是调用CreateIoCompletionPort,但这次的作用不同),注意,按道理来讲,此时传递给CreateIoCompletionPort的第三个参数应该是一个完成键,一般来讲,程序都是传递一个单句柄数据结构的地址,该单句柄数据包含了和该客户端连接有关的信息,由于我们只关心套接字句柄,所以直接将套接字句柄作为完成键传递;
      (3).触发一个WSARecv异步调用,这次又用到了尾随数据,使接收数据所用的缓冲区紧跟在WSAOVERLAPPED对象之后,此外,还有操作类型等重要信息
      在工作者线程的循环中,我们
      1.调用GetQueuedCompletionStatus取得本次I/O的相关信息(例如套接字句柄传送的字节数单I/O数据结构的地址等等)
      2.通过单I/O数据结构找到接收数据缓冲区,然后将数据原封不动的发送到客户端
      3.再次触发一个WSARecv异步操作
      


      IP属地:福建4楼2011-05-30 17:52
      回复



        IP属地:福建6楼2011-05-30 17:55
        回复