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

winsock IO模型之四重叠IO

只看楼主收藏回复

你发那么多干嘛!!!!!不会等一下啊!!!!!凑字,凑字,凑字。。。凑字。


IP属地:福建1楼2011-05-30 17:45回复
            &g_pPerIODataArr[g_iTotalConn]->overlap,
            NULL);
        //WSARecv的参数中都有一个 Overlapped 参数,我们可以假设是把我们的WSARecv这样的操作“绑定”到这个重叠结构上,
        //提交一个请求,而不是将操作立即完成,其他的事情就交给重叠结构去做,而其中重叠结构又要与Windows的事件对象“绑定”在一起,
           // 这样我们调用完 WSARecv 以后就可以“坐享其成”,等到重叠操作完成以后,自然会有与之对应的事件来通知我们操作完成,
    //然后我们就可以来根据重叠操作的结果取得我们想要的数据了。
        g_iTotalConn++;
    }
    closesocket(sListen);
    WSACleanup();
    return 0;
    }
    DWORD WINAPI WorkerThread(LPVOID lpParam)
    {
    int ret, index;
    DWORD cbTransferred;
    while (TRUE)
    {
          //判断出一个重叠 I/O 调用是否完成
        ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE);
        if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
        {
          continue;
        }
    index = ret - WSA_WAIT_EVENT_0;
    WSAResetEvent(g_CliEventArr[index]);//手动设置为 未传信
    WSAGetOverlappedResult(
    g_CliSocketArr[index],
    &g_pPerIODataArr[index]->overlap,
    &cbTransferred,
    TRUE,
    &g_pPerIODataArr[g_iTotalConn]->Flags);//判断该重叠调用到底是成功,还是失败
    if (cbTransferred == 0)
    {
        //客户端连接关闭
        Cleanup(index);
    }
    else
    {
         // g_pPerIODataArr[index]->szMessage保存了接受到的数据
        g_pPerIODataArr[index]->szMessage[cbTransferred] = '\0';
        send(g_CliSocketArr[index], g_pPerIODataArr[index]->szMessage,\
        cbTransferred, 0);
         // 进行另一个异步操作
        WSARecv(
           g_CliSocketArr[index],
           &g_pPerIODataArr[index]->Buffer,
           1,
           &g_pPerIODataArr[index]->NumberOfBytesRecvd,
           &g_pPerIODataArr[index]->Flags,
           &g_pPerIODataArr[index]->overlap,
           NULL);
    }
    }
    return 0;
    }
    void Cleanup(int index)
    {
       closesocket(g_CliSocketArr[index]);
       WSACloseEvent(g_CliEventArr[index]);
       HeapFree(GetProcessHeap(), 0, g_pPerIODataArr[index]);
       if (index < g_iTotalConn - 1)
       {  
         g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];
         g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];
         g_pPerIODataArr[index] = g_pPerIODataArr[g_iTotalConn - 1];
    


    IP属地:福建3楼2011-05-30 17:46
    回复
                                                                 HEAP_ZERO_MEMORY,
                                                                 sizeof(PER_IO_OPERATION_DATA)
                                                                 );
              lpPerIOData->Buffer.len = MSGSIZE;
              lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
              lpPerIOData->sClient = g_sNewClientConnection;
           WSARecv(lpPerIOData->sClient,
           &lpPerIOData->Buffer,
           1,
           &lpPerIOData->NumberOfBytesRecvd,
           &lpPerIOData->Flags,
           &lpPerIOData->overlap,
           CompletionROUTINE);
           g_bNewConnectionArrived = FALSE;
           }
          SleepEx(1000, TRUE);
         }
      return 0;
      }
      void CALLBACK CompletionROUTINE(DWORD dwError,
      DWORD cbTransferred,
      LPWSAOVERLAPPED lpOverlapped,
      DWORD dwFlags)
      {
         LPPER_IO_OPERATION_DATA lpPerIOData = (LPPER_IO_OPERATION_DATA)lpOverlapped;
         if (dwError != 0 || cbTransferred == 0)
         {
           // 客户端关闭
           closesocket(lpPerIOData->sClient);
           HeapFree(GetProcessHeap(), 0, lpPerIOData);
         }
         else
         {
           lpPerIOData->szMessage[cbTransferred] = '\0';
           send(lpPerIOData->sClient, lpPerIOData->szMessage, cbTransferred, 0);
           // 开启另一个异步操作
           memset(&lpPerIOData->overlap, 0, sizeof(WSAOVERLAPPED));
           lpPerIOData->Buffer.len = MSGSIZE;
           lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
           WSARecv(lpPerIOData->sClient,
                   &lpPerIOData->Buffer,
                   1,
                   &lpPerIOData->NumberOfBytesRecvd,
                   &lpPerIOData->Flags,
                   &lpPerIOData->overlap,
                   CompletionROUTINE);
         }
      }
      用完成例程来实现重叠I/O比用事件通知简单得多。在这个模型中,主线程只用不停的接受连接即可;辅助线程判断有没有新的客户端连接被建立,如果有,就为那个客户端套接字激活一个异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后CompletionROUTINE可以被内核调用。如果辅助线程不调用SleepEx,则内核在完成一次I/O操作后,无法调用完成例程(因为完成例程的运行应该和当初激活WSARecv异步操作的代码在同一个线程之内)
      完成例程内的实现代码比较简单,它取出接收到的数据,然后将数据原封不动的发送给客户端,最后重新激活另一个WSARecv异步操作。注意,在这里用到了尾随数据,我们在调用WSARecv的时候,参数lpOverlapped实际上指向一个比它大得多的结构PER_IO_OPERATION_DATA,这个结构除了WSAOVERLAPPED以外,还被我们附加了缓冲区的结构信息,另外还包括客户端套接字等重要的信息这样,在完成例程中通过参数lpOverlapped拿到的不仅仅是WSAOVERLAPPED结构,还有后边尾随的包含客户端套接字和接收数据缓冲区等重要信息。这样的C语言技巧在我后面介绍完成端口的时候还会使用到
      


      IP属地:福建5楼2011-05-30 17:46
      回复
        结果图:



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



          IP属地:福建7楼2011-05-30 17:50
          回复