一个对Winsock 完成端口模型封装的类

一个对Winsock 完成端口模型封装的类

/*++

Copyright (c) 2004

模块名:

     iomodel.h

模块描述:

     Winsock 完成端口类头文件


开发环境:
   
     Visual C++ 6.0, Windows 2000.
    
修订记录:

     创建于: 2004.1.16

最后修改日期:
      2004.1.23


--*/

#ifndef      _IOMODEL_H
#define      _IOMODEL_H

//
//Head files
//
#include <winsock2.h>
#include <mswsock.h>


/
/
/

#ifdef __cplusplus
extern "C" {
#endif

       
#define    BUFFER_SIZE           4096
#define    MAXTHREAD_COUNT       8

#define    PORT                  8080
#define    LOCALADDRESS          "172.29.90.96"

#define    IO_READ_COMPLETION    100
#define    IO_WRITE_COMPLETION   200
#define    IO_ACCEPT_COMPLETION  300


//
//自定义枚举数据类型,用来标识套接字IO动作类型
//
typedef enum _IO_OPERATION
{
        IoAccept, //AcceptEx/accept
  IoRead,   //WSARecv/recv/ReadFile
  IoWrite,   //WSASend/send/WriteFile
  IoEnd
}IO_OPERATION, *PIO_OPERATION;

//
//自定义结构,即“完成键”(单句柄数据)
//
typedef struct _PER_HANDLE_CONTEXT
{
 SOCKET                     IoSocket;

 _PER_HANDLE_CONTEXT*       pNext;
}PER_HANDLE_CONTEXT, *PPER_HANDLE_CONTEXT;


//
//单IO数据,扩展的WSAOVERLAPPED
//
typedef struct _PER_IO_CONTEXT
{
 WSAOVERLAPPED              ol;
 char                       szBuffer[BUFFER_SIZE];
 WSABUF                     wsaBuffer;
 SOCKET                     sClient;

 unsigned int               unId;

 IO_OPERATION               IoOperation;

 _PER_IO_CONTEXT*           pNext;
}PER_IO_CONTEXT, *PPER_IO_CONTEXT;

//
// global var
//

static  GUID g_GUIDAcceptEx = WSAID_ACCEPTEX;
static  GUID g_GUIDTransmitFile = WSAID_TRANSMITFILE;

DWORD __stdcall   CompletionRoutine(LPVOID);


//
//完成端口模型类
//


class CompletionPortModel
{
public:
 CompletionPortModel();
 ~CompletionPortModel();

 BOOL                Init();
 BOOL                ThreadLoop();
 BOOL                AllocEventMessage();
 BOOL                PostAcceptEx();
 
 virtual BOOL        HandleData(
         PPER_IO_CONTEXT lpPerIoContext,
            int nFlags
         );
 virtual BOOL        DataAction(
            PPER_IO_CONTEXT lpPerIoContext,
            PPER_HANDLE_CONTEXT lpNewperHandletext
            );
 
 void                InsertNode(PPER_IO_CONTEXT pNode, PPER_HANDLE_CONTEXT pHandleNode);
 void                ReleaseNode(PPER_IO_CONTEXT pNode);
 void                InsertToLookaside(PPER_IO_CONTEXT lpIoNode, PPER_HANDLE_CONTEXT lpHandleNode);

 PPER_IO_CONTEXT     GetIoFromLookaside();
 PPER_HANDLE_CONTEXT GetHandleFromLookaside();


 


 HANDLE                        m_hCOP;
 SOCKET                        m_ListenSocket;
 
 CRITICAL_SECTION              m_ListCriSection;
 CRITICAL_SECTION              m_HandleCriSection;
 CRITICAL_SECTION              m_IoCriSection;

 LPFN_TRANSMITFILE             lpTransmitFile;

 volatile PPER_IO_CONTEXT      m_lpIoLookasideLists;
 volatile PPER_HANDLE_CONTEXT  m_lpHandleLOOKasideLists;
 
protected:
 BOOL                InitWinsock();
 BOOL                BindAndListenSocket();
 BOOL                InitLinkListHead();
 void                CloseThreadHandle();
 void                GetAddressAndPort();

 
 UINT                uPort;
 char                szAddress[20];
 
 HANDLE                        m_hThreadArray[MAXTHREAD_COUNT];
 HANDLE                        m_hEvent;
 
 volatile LONG                 m_lAcceptExCounter;
 volatile PPER_IO_CONTEXT      m_lpConnectionListHead;

 LPFN_ACCEPTEX                 lpAcceptEx;

private:

};


#ifdef __cplusplus
}
#endif

#endif  //_IOMODEL_H

================================================================================

/*++

Copyright (c) 2004

模块名:

     iomodel.cpp

模块描述:

     Winsock 完成端口类实现文件

作者:

     PPP elssann@hotmail.com

开发环境:
   
     Visual C++ 6.0, Windows 2000.
    
修订记录:

     创建于: 2004.1.16

最后修改日期:
      2004.1.23


--*/

#include <iostream.h>
#include <winsock2.h>
#include <mswsock.h>
#include "iomodel.h"


CompletionPortModel::CompletionPortModel()
/*++

函数描述:
    构造函数,初始化线程句柄数组,初始化AcceptEx()调用的计数。初始化临界段代码变量。

Arguments:
     无。

Return Value:
     无。

--*/

{
 for (int i=0; i< MAXTHREAD_COUNT; i++)
 {
  m_hThreadArray[i] = INVALID_HANDLE_VALUE;
 }

 m_lAcceptExCounter = 0;

 InitializeCriticalSection(&m_ListCriSection);
 InitializeCriticalSection(&m_HandleCriSection);
 InitializeCriticalSection(&m_IoCriSection);

 m_lpHandleLOOKasideLists = NULL;
 m_lpIoLookasideLists = NULL;

#ifndef _DEBUG
 GetAddressAndPort();
#endif
}//end of CompletionPortModel()

CompletionPortModel::~CompletionPortModel()
/*++

函数描述:
    析构函数,释放链表所有结点。

Arguments:
     无。

Return Value:

--*/
{
 PPER_IO_CONTEXT lpIoNode;

 while (m_lpConnectionListHead->pNext)
 {
  lpIoNode = m_lpConnectionListHead->pNext;
  m_lpConnectionListHead->pNext = lpIoNode->pNext;
  closesocket(lpIoNode->sClient);
  HeapFree(GetProcessHeap(), 0, lpIoNode);
 }

 while(NULL != m_lpIoLookasideLists)
 {
  lpIoNode = m_lpIoLookasideLists;
  m_lpIoLookasideLists = m_lpIoLookasideLists->pNext;
  HeapFree(GetProcessHeap(), 0, lpIoNode);
 }

 PPER_HANDLE_CONTEXT lpHandleNode;
 while(NULL != m_lpHandleLOOKasideLists)
 {
  lpHandleNode = m_lpHandleLOOKasideLists;
  m_lpHandleLOOKasideLists = m_lpHandleLOOKasideLists->pNext;
  HeapFree(GetProcessHeap(), 0, lpHandleNode);
 }

 DeleteCriticalSection(&m_ListCriSection);
 DeleteCriticalSection(&m_HandleCriSection);
 DeleteCriticalSection(&m_IoCriSection);
 
}//end of ~CompletionPortModel()


BOOL CompletionPortModel::Init()
/*++

函数描述:
    初始化,创建完成端口、创建完成端口线程,并调用类成员函数InitWinsock初始化Winsock、
建立一个监听套接字m_ListenSocket,并将此套接字同完成端口关联起来,获取AcceptEx指针。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。

--*/
{
    BOOL bSuccess = InitLinkListHead();
 
 if (FALSE == bSuccess)
 {
  return FALSE;
 }
 
 m_hCOP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
 if (NULL == m_hCOP)
 {
  cout << "CreateIoCompletionPort() failed: " << GetLastError() << endl;

  return FALSE;
 }

 //
 //取得系统中CPU的数目,创建和CPU数目相等的线程,如果事先估计到完成端口处理线程会堵塞,
 //可以考虑创建 SysInfo.dwNumberOfProcessors*2个线程。一般在单处理器上创建和CPU数目相等
 //的线程就可以了
 //
 SYSTEM_INFO SysInfo;
 GetSystemInfo(&SysInfo);
 if (MAXTHREAD_COUNT < SysInfo.dwNumberOfProcessors)
 {
  SysInfo.dwNumberOfProcessors = MAXTHREAD_COUNT;
 }

 for (int i=0; i<(int)SysInfo.dwNumberOfProcessors; i++)
 {
  m_hThreadArray[i] = CreateThread(NULL, 0, CompletionRoutine, (LPVOID)this, 0, NULL);
  if (NULL == m_hThreadArray[i])
  {
   while (i>0)
   {
    CloseHandle(m_hThreadArray[i-1]);
    m_hThreadArray[i-1] = INVALID_HANDLE_VALUE;
    i--;
   }//end of while

   cout << "CreateThread() failed: " << GetLastError() << endl;
   CloseHandle(m_hCOP);
   HeapFree(GetProcessHeap(), 0, m_lpConnectionListHead);
   
   return FALSE;
  }
 }//end of for

 //
 //调用InitWinsock函数初始化Winsock、建立一个监听套接字m_ListenSocket,
 //并将此套接字同完成端口关联起来,获取AcceptEx指针。
 //
 bSuccess = InitWinsock();
 if (!bSuccess)
 {
  //
  //给完成端口线程发送消息,指示线程退出。
  //
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  CloseThreadHandle();
  CloseHandle(m_hCOP);
  HeapFree(GetProcessHeap(), 0, m_lpConnectionListHead); 

  return FALSE;
 }

 //
 //调用BindAndListenSocket()绑定套接字并将套接字置于监听状态
 //
 bSuccess = BindAndListenSocket(); 
 if (!bSuccess)
 {
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  CloseThreadHandle();
  CloseHandle(m_hCOP);
  HeapFree(GetProcessHeap(), 0, m_lpConnectionListHead);  
  
  return FALSE;
 }

 return TRUE; 
}//end of Init()


void CompletionPortModel::CloseThreadHandle()
/*++

函数描述:
    对每一个创建的线程调用CloseHandle()。

Arguments:
     无。

Return Value:
     无。

--*/
{
 for (int i=0; i< MAXTHREAD_COUNT; i++)
 {
  if (INVALID_HANDLE_VALUE != m_hThreadArray[i])
  {
   CloseHandle(m_hThreadArray[i]);
   m_hThreadArray[i] = INVALID_HANDLE_VALUE;
  }
 }//end of for
 
 return;
}//end of CloseThreadHandle()


BOOL CompletionPortModel::InitWinsock()
/*++

函数描述:
    初始化Winsock,创建一个监听套接字,获取AcceptEx函数指针,为监听套接字分配一个单句柄
 数据,并将监听套接字与完成端口hCOP关联。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。

--*/
{
 WSADATA wsd;
 int nResult = WSAStartup(MAKEWORD(2,2), &wsd);
 if (0 != nResult)
 {
  cout << "WSAStartup() failed" << endl;
  
  return FALSE;
 }

 m_ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP,
          NULL, 0, WSA_FLAG_OVERLAPPED);
    if (INVALID_SOCKET == m_ListenSocket)
    {
  cout << "WSASocket() failed: " << WSAGetLastError() << endl;
        WSACleanup();
       
        return FALSE;
    }
 
 
 DWORD dwResult;

 //
 //获取微软SOCKET扩展函数指针
 //
 nResult = WSAIoctl(
      m_ListenSocket,
      SIO_GET_EXTENSION_FUNCTION_POINTER,
      &g_GUIDAcceptEx,
      sizeof(g_GUIDAcceptEx),
      &lpAcceptEx,
      sizeof(lpAcceptEx),
        &dwResult,
      NULL,
      NULL
      );

 if (SOCKET_ERROR == nResult)
 {
  cout << "Get AcceptEx failed: " << WSAGetLastError() << endl;
  closesocket(m_ListenSocket);
        WSACleanup();

  return FALSE;
 }

 nResult = WSAIoctl( 
      m_ListenSocket,
      SIO_GET_EXTENSION_FUNCTION_POINTER,
      &g_GUIDTransmitFile,
      sizeof(g_GUIDTransmitFile),
      &lpTransmitFile,
      sizeof(lpTransmitFile),
      &dwResult,
      NULL,
      NULL
      );
 
 if (SOCKET_ERROR == nResult)
 {
  cout << "Get TransmitFile failed: " << WSAGetLastError() << endl;
  closesocket(m_ListenSocket);
        WSACleanup();
  
  return FALSE;
 }


 //
 //为监听套接字分配一个单句柄数据
 //
 PPER_HANDLE_CONTEXT lpListenHandleContext = (PPER_HANDLE_CONTEXT)HeapAlloc(
                    GetProcessHeap(), HEAP_ZERO_MEMORY,
                    sizeof(PER_HANDLE_CONTEXT)
                      );
 if (NULL == lpListenHandleContext)
 {
  closesocket(m_ListenSocket);
        WSACleanup();

  cout << "HeapAlloc() failed " << endl;


  return FALSE;
 }

 lpListenHandleContext->IoSocket = m_ListenSocket;
 lpListenHandleContext->pNext = NULL;

 //
 //将监听套接字m_ListenSocket和已经建立的完成端口关联起来
 //
 HANDLE hrc = CreateIoCompletionPort(
          (HANDLE)m_ListenSocket,
          m_hCOP,
          (ULONG_PTR)lpListenHandleContext,
          0
          );
 if (NULL == hrc)
 {
  closesocket(m_ListenSocket);
  HeapFree(GetProcessHeap(), 0, lpListenHandleContext);
  WSACleanup();

  cout << "CreateIoCompletionPort failed: " << GetLastError() << endl;
  
  return FALSE;
 }

 return TRUE;
}//end of InitWinsock()


BOOL CompletionPortModel::BindAndListenSocket()
/*++

函数描述:
    private函数,供Init调用。
 将监听套接字m_ListenSocket绑定到本地IP地址,并置于监听模式。


Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。

--*/
{
    SOCKADDR_IN InternetAddr;
    InternetAddr.sin_family = AF_INET;

#ifdef _DEBUG
    InternetAddr.sin_addr.s_addr = inet_addr(LOCALADDRESS);
    InternetAddr.sin_port = htons(PORT);  
#else
    InternetAddr.sin_addr.s_addr = inet_addr(szAddress);
    InternetAddr.sin_port = htons(uPort);    
#endif 
   
    int nResult = bind(m_ListenSocket, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr));
    if (SOCKET_ERROR == nResult)
    {
        WSACleanup();
  closesocket(m_ListenSocket);
  
  cout << "bind() failed: " << WSAGetLastError() << endl;
       
        return FALSE;
    } 

 nResult = listen(m_ListenSocket, 20);
    if (SOCKET_ERROR == nResult)
    {
        WSACleanup();
  closesocket(m_ListenSocket);

  cout << "listen() failed: " << WSAGetLastError() << endl;
       
        return FALSE;
    }  

 return TRUE;
}//end of BindAndListenSocket()


DWORD __stdcall CompletionRoutine(LPVOID Param)
/*++

函数描述:
    完成端口处理线程,循环调用GetQueuedCompletionStatus来获取IO操作结果。

Arguments:

Return Value:
     线程退出代码。

--*/
{
 CompletionPortModel* pThis = (CompletionPortModel*)Param;
 DWORD dwNumberBytes;
 PPER_HANDLE_CONTEXT lpHandleContext = NULL;
 LPWSAOVERLAPPED lpOverlapped = NULL;
 int nResult;
 BOOL bSuccess;

 while (TRUE)
 {
  bSuccess = GetQueuedCompletionStatus(
           pThis->m_hCOP,
           &dwNumberBytes,
           (PULONG_PTR )&lpHandleContext,
           &lpOverlapped,
           INFINITE
           );


  if (FALSE == bSuccess)
  {

#ifndef _DEBUG
   cout << "GetQueuedCompletionStatus() failed: " << GetLastError() << endl;
#endif

   continue;
  }
  if (NULL == lpHandleContext)
  {
   //
   //PostQueuedCompletionStatus发过来一个空的单句柄数据,表示线程要退出了。
   //
   return 0;
  }

  PPER_IO_CONTEXT lpPerIoContext = (PPER_IO_CONTEXT)lpOverlapped;

#ifdef _DEBUG
  cout << "recv buffer data: " << lpPerIoContext->szBuffer << endl;  
#endif
  
  if(IoAccept != lpPerIoContext->IoOperation)
  {
   if((!bSuccess) || (bSuccess && (0 == dwNumberBytes)))
   {
    closesocket(lpPerIoContext->sClient);
    lpPerIoContext->pNext = NULL;
    pThis->InsertToLookaside(lpPerIoContext, NULL);
    lpHandleContext->pNext = NULL;
    pThis->InsertToLookaside(NULL, lpHandleContext);
    
    continue;
   }
  }

  HANDLE hResult;
  PPER_HANDLE_CONTEXT lpNewperHandleContext;

  switch(lpPerIoContext->IoOperation)
  {
  case IoAccept :
   if (dwNumberBytes)
   {
    //
    //第一次连接成功并且收到了数据,将这个结点从链表中解除
    //
    EnterCriticalSection(&pThis->m_ListCriSection);
    pThis->ReleaseNode(lpPerIoContext);
    LeaveCriticalSection(&pThis->m_ListCriSection);
   }
   nResult = setsockopt(
        lpPerIoContext->sClient,
        SOL_SOCKET,
        SO_UPDATE_ACCEPT_CONTEXT,
        (char *)&pThis->m_ListenSocket,
        sizeof(pThis->m_ListenSocket)
        );
   if(SOCKET_ERROR == nResult)
   {
    cout << "SO_UPDATE_ACCEPT_CONTEXT failed to update accept socket" << endl;
    closesocket(lpPerIoContext->sClient); 
    lpPerIoContext->pNext = NULL;
    pThis->InsertToLookaside(lpPerIoContext, NULL);
    
    continue;
   }

   
   lpNewperHandleContext = pThis->GetHandleFromLookaside();
   if (NULL == lpNewperHandleContext)
   {
    lpNewperHandleContext = (PPER_HANDLE_CONTEXT)HeapAlloc(
     GetProcessHeap(),
     HEAP_ZERO_MEMORY,
     sizeof(PER_HANDLE_CONTEXT)
     );
    if (NULL == lpNewperHandleContext)
    {
     cout << "HeapAlloc() for lpNewperHandlecontext failed" << endl;
     
     closesocket(lpPerIoContext->sClient);
     lpPerIoContext->pNext = NULL;
     pThis->InsertToLookaside(lpPerIoContext, NULL);
     
     continue;
    }    
   }

   lpNewperHandleContext->IoSocket = lpPerIoContext->sClient;
   lpNewperHandleContext->pNext = NULL;
   
   //
   //将新建立的套接字关联到完成端口
   //
   hResult = CreateIoCompletionPort(
           (HANDLE)lpPerIoContext->sClient,/
           pThis->m_hCOP,
           (DWORD_PTR)lpNewperHandleContext,
           0
           );
   if (NULL == hResult)
   {
    cout << "CreateIoCompletionPort() failed: " << GetLastError();

    closesocket(lpPerIoContext->sClient);
    lpPerIoContext->pNext = NULL;
    lpNewperHandleContext->pNext = NULL;
    pThis->InsertToLookaside(lpPerIoContext, NULL);
    pThis->InsertToLookaside(NULL, lpNewperHandleContext);
    
    continue;
   }

   if (dwNumberBytes)
   {
    //
    //分析处理数据。
    //
    pThis->HandleData(lpPerIoContext, IO_READ_COMPLETION);
    bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
    if (FALSE == bSuccess)
    {
     continue;
    }
   }

   //
   //如果连接成功但是没有收到数据
   //
   else
   {
    pThis->HandleData(lpPerIoContext, IO_ACCEPT_COMPLETION);
    bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
    if (FALSE == bSuccess)
    {
     continue;
    }
   }
   break;//end of case IoAccept
   
  case IoRead:
   pThis->HandleData(lpPerIoContext, IO_READ_COMPLETION);
   bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
   if (FALSE == bSuccess)
   {
    continue;
   }

   break;//end of case IoRead

  case IoWrite:
   pThis->HandleData(lpPerIoContext, IO_WRITE_COMPLETION);
   bSuccess = pThis->DataAction(lpPerIoContext, lpNewperHandleContext);
   if (FALSE == bSuccess)
   {
    continue;
   } 

   break;

  default:
   continue;
   break;
  }
 }

 return 0;

}//end of CompletionRoutine()

BOOL CompletionPortModel::PostAcceptEx()
/*++

Fucntion Description:

 连续发出10个AcceptEx调用。

Arguments:

Return Value:

 函数调用成功返回TRUE,失败返回FALSE。
 
--*/
{
  while (m_lAcceptExCounter < 10)
  {
   SOCKET AcceptSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, /
          NULL, 0, WSA_FLAG_OVERLAPPED);  
   if (INVALID_SOCKET == AcceptSocket)
   {
    cout << "WSASocket failed " << endl;
    
    return FALSE;
   }

   PPER_IO_CONTEXT lpAcceptExIoContext = GetIoFromLookaside();
   if (NULL == lpAcceptExIoContext)
   {
    lpAcceptExIoContext = (PPER_IO_CONTEXT)HeapAlloc(/
     GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT));
    if (NULL == lpAcceptExIoContext)
    {
     cout << "HeapAlloc() failed " << endl;
     closesocket(AcceptSocket);
     
     return FALSE;
    }
   }

   ZeroMemory(&(lpAcceptExIoContext->ol), sizeof(lpAcceptExIoContext->ol));
   lpAcceptExIoContext->sClient = AcceptSocket;
   lpAcceptExIoContext->IoOperation = IoAccept;
   lpAcceptExIoContext->pNext = NULL;
   ZeroMemory(lpAcceptExIoContext->szBuffer, BUFFER_SIZE);
   lpAcceptExIoContext->wsaBuffer.buf = lpAcceptExIoContext->szBuffer;
   lpAcceptExIoContext->wsaBuffer.len = BUFFER_SIZE;
   lpAcceptExIoContext->unId = lpAcceptExIoContext->sClient;
   
   DWORD dwBytes;
   BOOL bSuccess = lpAcceptEx(
     m_ListenSocket,
     lpAcceptExIoContext->sClient,
     lpAcceptExIoContext->szBuffer,
     lpAcceptExIoContext->wsaBuffer.len - ((sizeof(SOCKADDR_IN) + 16) * 2),
     sizeof(SOCKADDR_IN) + 16,
     sizeof(SOCKADDR_IN) + 16,
     &dwBytes,
     &(lpAcceptExIoContext->ol));

   if (FALSE == bSuccess)
   {
    int nResult = WSAGetLastError();
    if (nResult != ERROR_IO_PENDING)
    {
     cout << "AcceptEx() failed :" << nResult << endl;
     closesocket(AcceptSocket);
     HeapFree(GetProcessHeap(), 0 , lpAcceptExIoContext);
     
     return FALSE;
    }
    
    InsertNode(lpAcceptExIoContext, NULL); 
    InterlockedExchangeAdd(&m_lAcceptExCounter, 1);
   }
  }

  InterlockedExchangeAdd(&m_lAcceptExCounter, -10);

 return TRUE;
}//end of PostAccetExRoutine()

void CompletionPortModel::InsertNode(PPER_IO_CONTEXT pNode, PPER_HANDLE_CONTEXT pHandleNode)
/*++

Fucntion Description:

 根据参数类型将传递进来结点插入到相应的链表头。

Arguments:

    pNode       -  要插入链表中的结点
 pHandleNode -  要插入链表中的结点
 
Return Value:

 无.

--*/
{
 if (NULL != pNode)
 {  
  EnterCriticalSection(&m_ListCriSection);
  pNode->pNext = m_lpConnectionListHead->pNext;
  m_lpConnectionListHead->pNext = pNode;
  LeaveCriticalSection(&m_ListCriSection);
 }

 return;
}//end of InsertNode


BOOL CompletionPortModel::ThreadLoop()
/*++

Fucntion Description:
 
   主线程循环,用WaitForSigleObject等待m_hEvent,已经发出的AcceptEx()调用耗尽,FD_ACCEPT
事件将被触发,WaitForSigleObject成功返回,然后调用PostAcceptEx()来新发出10个AcceptEx()调用。
WaitForSigleObject每次等待10秒,超时返回后,对系统中已经建立成功了的并且还没有收发过数据的
SOCKET连接进行检测,如果某个连接已经建立了30秒,并且还没收发过数据,则强制关闭。

Arguments:
    
   无。

Return Value:
     
   函数调用成功返回TRUE,调用失败返回FALSE;
    
--*/
{
 int nOptval;
 int nOptlen;
 int nResult;
 DWORD dwResult;
 int nCounter = 0;

#ifdef _DEBUG
 int nTimeOut = 0;
#endif

 cout << "Server is running.........." << nCounter << " times" << endl; 
 
 while (TRUE)
 {  
  dwResult = WaitForSingleObject(m_hEvent, 10000);
 
  if (WAIT_FAILED == dwResult)
  {
   PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
   cout << "WSAWaitForMultipleEvents() failed: " << WSAGetLastError() << endl;

   return FALSE;
  }
  
  if (WAIT_TIMEOUT == dwResult)
  { 
   nCounter++;
   cout << "Server is running.........." << nCounter << " times" << endl;
   
#ifdef _DEBUG
   nTimeOut++;
   cout << nTimeOut << "*******TIME_OUT********" << nTimeOut << endl;
#endif
   
   PPER_IO_CONTEXT lpCurentNode = m_lpConnectionListHead->pNext;
   PPER_IO_CONTEXT lpPreNode = m_lpConnectionListHead;
   PPER_IO_CONTEXT lpTempNode; 
   
   while (NULL != lpCurentNode)
   { 
    EnterCriticalSection(&m_ListCriSection);
    nOptlen = sizeof(nOptval);
    nResult = getsockopt(
     lpCurentNode->sClient,
     SOL_SOCKET,
     SO_CONNECT_TIME,
     (char*)&nOptval,
     &nOptlen
     );
#ifdef _DEBUG
    cout << "nOptval = " << nOptval << endl;
#endif _DEBUG
    
    if (SOCKET_ERROR == nResult)
    {
     cout << "SO_CONNECT_TIME failed: " << WSAGetLastError() << endl;
     lpPreNode = lpCurentNode;
     lpCurentNode = lpCurentNode->pNext;
     LeaveCriticalSection(&m_ListCriSection);
     
     continue;
    }
    if ((nOptval!=0xFFFFFFFF) && (nOptval>30))
    {
     lpPreNode->pNext = lpCurentNode->pNext;
     lpTempNode = lpCurentNode;
     lpCurentNode = lpCurentNode->pNext;
     closesocket(lpTempNode->sClient);
     lpTempNode->pNext = NULL;
     InsertToLookaside(lpTempNode, NULL);
    }
    else
    {
     lpPreNode = lpCurentNode;
     lpCurentNode = lpCurentNode->pNext;
    }
    LeaveCriticalSection(&m_ListCriSection);
   }
  }
  else
  {
   if (WAIT_TIMEOUT != dwResult)
   {
    if (FALSE == PostAcceptEx())
    {
     PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
     
     return FALSE;
    }
   }
  }
 }

 return TRUE;
}//end of CheckConnectTime

void CompletionPortModel::ReleaseNode(PPER_IO_CONTEXT pNode)
/*++

Fucntion Description:

     将参数中传递的结点从链表中解除,但不释放结点。以便不让ThreadLoop函数对其进行超时检测。
此函数在完成端口线程里收发数据成功后调用。

Arguments:
    
  要从链表中释放的结点。

Return Value:

     无。
    
--*/
{
 PPER_IO_CONTEXT pTempNode = m_lpConnectionListHead->pNext;
 PPER_IO_CONTEXT pPreNode =m_lpConnectionListHead;
 PPER_IO_CONTEXT pDeleteNode;
 
 while (NULL != pTempNode)
 {
  if (pNode->unId == pTempNode->unId)
  {  
   pPreNode->pNext = pTempNode->pNext;
   pDeleteNode = pTempNode;
   pTempNode = pTempNode->pNext;
   
   return;
  }
  else
  { 
   pPreNode = pTempNode;
   pTempNode = pTempNode->pNext;
  }
 }

 return;
}//end of RealeseNode


BOOL CompletionPortModel::HandleData(PPER_IO_CONTEXT lpPerIoContext, int nFlags)
/*++

Fucntion Description:

      根据传进来的nFlags参数对lpPerIoContext进行设置,并指示下一步IO操作。

Arguments:
    
      lpPerIoContext - 调用GetQueueCompletionStatus函数得到的上一次IO操作的结果(扩展的
                      WSAOVERLAPPED结构)。
      nFlags         - 指明已经完成上一次IO的操作类型。

Return Value:

      函数调用成功返回TRUE,失败返回FALSE。
    
--*/
{
 //
 //nFlags == IO_READ_COMPLETION表示完成的上一次IO操作是WSARecv。
 //
 if (IO_READ_COMPLETION == nFlags)
 {
  //
  //完成了WSARecv,接下来需要调用WSASend把刚接收到的数据发送回去,把
  //lpPerIoContext->ContinueAction = ContinueWrite;
  //
  lpPerIoContext->IoOperation = IoWrite;
  ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
  
  //
  //接收到的数据在lpPerIoContext->wsaBuffer.buf里,可以调用
  //自定义函数对数据自行处理,本例中,简单的将数据再发送回去
  //
  strcpy(lpPerIoContext->szBuffer, lpPerIoContext->wsaBuffer.buf);
  lpPerIoContext->wsaBuffer.buf = lpPerIoContext->szBuffer;
  lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
  
  return TRUE;
 }

 if (IO_WRITE_COMPLETION == nFlags)
 {
  //
  //上一次IO操作WSASend数据发送完成,将后续操作标志设置为关闭
  //如果不需要关闭而是要继续发送,将lpPerIoContext->IoOperation设置为
  //IoWrite,如果要继续接收,将lpPerIoContext->IoOperation设置为
  //IoRead,并初始化好BUFFER,本例中,设置关闭
  //
  lpPerIoContext->IoOperation = IoEnd;

  return TRUE;
 }
 if (IO_ACCEPT_COMPLETION == nFlags)
 {
  //
  //刚建立了一个连接,并且没有收发数据,,,,
  //
  lpPerIoContext->IoOperation = IoRead;
  ZeroMemory(&(lpPerIoContext->ol), sizeof(WSAOVERLAPPED));
  ZeroMemory(lpPerIoContext->szBuffer, BUFFER_SIZE);
  lpPerIoContext->wsaBuffer.len = BUFFER_SIZE;
  lpPerIoContext->wsaBuffer.buf = lpPerIoContext->szBuffer;

  return TRUE;
 }
 
 
 return FALSE;
}// end of HandleData()


BOOL CompletionPortModel::InitLinkListHead()
/*++

Fucntion Description:

     初始化链表头指针。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。
    
--*/
{
 m_lpConnectionListHead = (PPER_IO_CONTEXT)HeapAlloc(GetProcessHeap(), /
  HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT));
 
 if (NULL == m_lpConnectionListHead)
 {
  cout << "HeapAlloc() failed " << endl;
  
  return FALSE;
 }
 m_lpConnectionListHead->pNext = NULL;
 
 return TRUE;
}// end of InitLinkListHead()

BOOL CompletionPortModel::AllocEventMessage()
/*++

Fucntion Description:

     将FD_ACCEPT事件注册到m_hEvent,这样当可用AcceptEx调用被耗尽的时候,就会触发FD_ACCEPT
  事件,然后ThreadLoop里的WaitForSingleObject就会成功返回,导致PostAcceptEx被调用。

Arguments:
     无。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。
    
--*/
{
 m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 if (NULL == m_hEvent)
 {
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  cout << "CreateEvent() failed: " << GetLastError() << endl;

  return FALSE;
 }
 
 int nResult = WSAEventSelect(m_ListenSocket, m_hEvent, FD_ACCEPT);
 if (SOCKET_ERROR == nResult)
 {
  PostQueuedCompletionStatus(m_hCOP, 0, NULL, NULL);
  CloseHandle(m_hEvent);

  cout << "WSAEventSeclet() failed: " << WSAGetLastError() << endl;
  
  return FALSE;
 }

 return TRUE;
}//end of AllocEventMessage()


BOOL CompletionPortModel::DataAction(PPER_IO_CONTEXT lpPerIoContext, PPER_HANDLE_CONTEXT lpNewperHandleContext)
/*++

Fucntion Description:

     根据参数lpPerIoContext的成员IoOperation的值来进行下一步IO操作。

Arguments:
    
  lpPerIoContext        - 将随WSASend或者WSARecv一起投递的扩展WSAOVERLAPPED结构。
  lpNewperHandleContext - AcceptEx调用成功后给新套接字分配的“单句柄数据”。

Return Value:
     函数调用成功返回TRUE,失败返回FALSE。
    
--*/
{
 int nResult;
 DWORD dwIosize = 0;
 DWORD dwFlags =0;
 if (IoWrite == lpPerIoContext->IoOperation)
 {
  nResult = WSASend(lpPerIoContext->sClient,
     &(lpPerIoContext->wsaBuffer),
     1,
     &dwIosize,
     0,
     &(lpPerIoContext->ol),
     NULL
     );
  if((SOCKET_ERROR==nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
  {
   cout << "WSASend() failed: " << WSAGetLastError() << endl;
   
   closesocket(lpPerIoContext->sClient);
   lpPerIoContext->pNext = NULL;
   lpNewperHandleContext->pNext = NULL;
   InsertToLookaside(lpPerIoContext, NULL);
   InsertToLookaside(NULL, lpNewperHandleContext);
   
   return FALSE;
  }
 }
 
 if (IoRead == lpPerIoContext->IoOperation)
 {
  nResult = WSARecv(lpPerIoContext->sClient,
     &(lpPerIoContext->wsaBuffer),
     1,
     &dwIosize,
     &dwFlags,
     &(lpPerIoContext->ol),
     NULL
     );
     
  if((SOCKET_ERROR==nResult) && (ERROR_IO_PENDING != WSAGetLastError()))
  {
   cout << "WSARecv() failed: " << WSAGetLastError() << endl;
    
   closesocket(lpPerIoContext->sClient);
   lpNewperHandleContext->pNext = NULL;
   lpPerIoContext->pNext = NULL;
   InsertToLookaside(lpPerIoContext, NULL);
   InsertToLookaside(NULL, lpNewperHandleContext);
     
   return FALSE;
  }
   
 }
    
 if (IoEnd == lpPerIoContext->IoOperation)
 {
  closesocket(lpPerIoContext->sClient);
  lpNewperHandleContext->pNext = NULL;
  InsertToLookaside(NULL, lpNewperHandleContext);
  lpPerIoContext->pNext = NULL;
  InsertToLookaside(lpPerIoContext, NULL);
 }

 return TRUE;
}// end of DataAction()


void CompletionPortModel::GetAddressAndPort()
/*++

Fucntion Description:

     由类构造函数调用的函数,用来输入服务器要绑定的本地IP地址和端口。

Arguments:
    
  无。

Return Value:
    
 无。  
    
--*/
{
 cout << "/nPlease input a port: ";
 cin >> uPort;
 cout << "/nPlease input localaddress:";
 cin >> szAddress;

 system("cls");

 return;
}// end of GetAddressAdnPort


void CompletionPortModel::InsertToLookaside(PPER_IO_CONTEXT lpIoNode, PPER_HANDLE_CONTEXT lpHandleNode)
/*++

Fucntion Description:

     给旁视列表的链表中插入一个空闲的结点。

Arguments:
    
  lpIoNode     - 要插入的结点,类型为PPER_IO_CONTEXT。
  lpHandleNode - 要插入的结点,类型为PPER_HANDLE_CONTEXT。

Return Value:
    
 无。  
    
--*/
{
 if (NULL != lpIoNode)
 {
  if (NULL == m_lpIoLookasideLists)
  {
   m_lpIoLookasideLists = lpIoNode;
   
   return;
  }
  lpIoNode->pNext = m_lpIoLookasideLists->pNext;
  m_lpIoLookasideLists->pNext = lpIoNode;
  
  return;
 }

 if (NULL != lpHandleNode)
 {
  if (NULL == m_lpHandleLOOKasideLists)
  {
   m_lpHandleLOOKasideLists = lpHandleNode;
   
   return;
  }
  lpHandleNode->pNext = m_lpHandleLOOKasideLists->pNext;
  m_lpHandleLOOKasideLists->pNext = lpHandleNode;
  
  return;
 }

 return;
}


PPER_IO_CONTEXT CompletionPortModel::GetIoFromLookaside()
/*++

Fucntion Description:

     从旁视列表中解除一个结点并将其返回。

Arguments:
    
  无。

Return Value:
    
 返回一个PPER_IO_CONTEXT类型的结点。  
    
--*/
{
 if (NULL == m_lpIoLookasideLists)
 {
  return NULL;
 }
 EnterCriticalSection(&m_IoCriSection);
 PPER_IO_CONTEXT lpReturnNode = m_lpIoLookasideLists;
 m_lpIoLookasideLists = m_lpIoLookasideLists->pNext;
 LeaveCriticalSection(&m_IoCriSection);

 return lpReturnNode;
}

PPER_HANDLE_CONTEXT CompletionPortModel::GetHandleFromLookaside()
/*++

Fucntion Description:

     从旁视列表中解除一个结点并将其返回。

Arguments:
    
  无。

Return Value:
    
 返回一个PPER_HANDLE_CONTEXT类型的结点。  
    
--*/
{
 if (NULL == m_lpHandleLOOKasideLists)
 {
  return NULL;
 }
 EnterCriticalSection(&m_HandleCriSection);
 PPER_HANDLE_CONTEXT lpReturnNode = m_lpHandleLOOKasideLists;
 m_lpHandleLOOKasideLists = m_lpHandleLOOKasideLists->pNext;
 LeaveCriticalSection(&m_HandleCriSection);
 
 return lpReturnNode;
}

================================================================================
/*++

Copyright (c) 2004

模块名:

     main.cpp

模块描述:

     主线程文件

作者:

     PPP elssann@hotmail.com

开发环境:
   
     Visual C++ 6.0, Windows 2000.
    
修订记录:

     创建于: 2004.1.16

最后修改日期:
      2004.1.23


--*/

#include "iomodel.h"
#include <winsock2.h>
#include <windows.h>
#include <iostream.h>

#pragma comment(lib, "ws2_32.lib")


void main()
{
 CompletionPortModel p;
 p.Init();
 p.AllocEventMessage();
 if (FALSE == p.PostAcceptEx())
 {
  return;
 }
 p.ThreadLoop();

 return;
}

 
WINDOWS下进行网络服务端程序开发,毫无疑问,Winsock 完成端口模型是最高效的。Winsock完成端口模型借助Widnows的重叠IO完成端口来实现,完成端口模型懂了之后是比较简单的,但是要想掌握Winsock完成端口模型,需要对WINDOWS下的线程、线程同步,Winsock API以及WINDOWS IO机制有一定的了解。如果不了解,推荐几本书:《Inside Windows 2000,《WINDOWS核心编程》,《WIN32多线程程序设计》、《WINDOWS网络编程技术》。在去年,我在C语言下用完成端口模型写了一个WEBSERVER,前些天,我决定用C++重写这个WEBSERVER,给这个WEBSERVER增加了一些功能,并改进完成端口操作方法,比如采用AcceptEx来代替accept和使用LOOKASIDE LIST来管理内存,使得WEBSERVER的性能有了比较大的提高。 (under the Windows network server program development, no doubt, Winsock completed port model is the most efficient. Winsock port model with complete preview of overlap and complete port IO to achieve complete port after the model to understand is a relatively simple, but want to know the complete Winsock port model, the need for the Windows threads, thread synchronization, Winsock API and Windows IO mechanism of a certain understanding. If we do not understand, recommended several books : "Inside Windows 2000," Windows core programming "," WIN32 multithreaded programming "," WINDOWS network programming technology. " Last year, I used C language under complete port model was a WEBSERVER, few days ago, I decided to rewrite the C WEBSERVER to the WEBSERVER i)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值