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

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;
}

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

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在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、付费专栏及课程。

余额充值