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

简介: BOOL CompletionPortModel::ThreadLoop()/*++ Fucntion Description:   主线程循环,用WaitForSigleObject等待m_hEvent,已经发出的AcceptEx()调用耗尽,FD_ACCEPT事件将被触发,WaitForSigleObject成功返回,然后调用PostAcceptEx()来新发出10个AcceptEx()调用。

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

目录
相关文章
|
Shell iOS开发
iOS 逆向编程(九 - 2)将端口映射、USB连接手机封装成 .sh 脚本
iOS 逆向编程(九 - 2)将端口映射、USB连接手机封装成 .sh 脚本
141 0
|
网络协议 Linux 网络安全
【计算机网络】网络通信基础(IP地址,端口号,五元组,OSI七层模型,TCP/IP五层模型,封装和分用)
随着时代发展,需要计算机之间相互通信,共享软件和数据,即多台计算机相互协同工作来完成某个业务,就有了网络互联
【计算机网络】网络通信基础(IP地址,端口号,五元组,OSI七层模型,TCP/IP五层模型,封装和分用)
|
C++ Windows
一个对Winsock 完成端口模型封装的类
2009-03-28 14:02 源代码说明: 在WINDOWS下进行网络服务端程序开发,毫无疑问,Winsock 完成端口模型是最高效的。
809 0
|
C++ Windows
一个对Winsock 完成端口模型封装的类
2009-03-28 14:02 源代码说明: 在WINDOWS下进行网络服务端程序开发,毫无疑问,Winsock 完成端口模型是最高效的。
782 0
一个对Winsock 完成端口模型封装的类【2】
BOOL CompletionPortModel::ThreadLoop()/*++ Fucntion Description:   主线程循环,用WaitForSigleObject等待m_hEvent,已经发出的AcceptEx()调用耗尽,FD_ACCEPT事件将被触发,WaitForSigleObject成功返回,然后调用PostAcceptEx()来新发出10个AcceptEx()调用。
629 0
|
4月前
|
弹性计算 应用服务中间件 Linux
阿里云服务器开放端口完整图文教程
笔者近期开发完成的服务端程序部署在阿里云的ECS云服务器上面,一些应用程序配置文件需要设置监听的端口(如Tomcat的8080、443端口等),虽然通过CentOs 7系统的的「防火墙」开放了对应的端口号,任然无法访问端口号对应的应用程序,后面了解到原来还需要设置云服务器的「安全组规则」,开放相应的端口权限,服务端的接口才能真正开放。
697 1
阿里云服务器开放端口完整图文教程
|
4月前
|
弹性计算 运维 数据安全/隐私保护
云服务器 ECS产品使用问题之如何更改服务器的IP地址或端口号
云服务器ECS(Elastic Compute Service)是各大云服务商阿里云提供的一种基础云计算服务,它允许用户租用云端计算资源来部署和运行各种应用程序。以下是一个关于如何使用ECS产品的综合指南。
|
3月前
|
缓存 NoSQL 网络安全
【Azure Redis 缓存】使用开源工具redis-copy时遇见6379端口无法连接到Redis服务器的问题
【Azure Redis 缓存】使用开源工具redis-copy时遇见6379端口无法连接到Redis服务器的问题
|
4月前
|
网络协议 Linux Unix
面试官:服务器最大可以创建多少个tcp连接以及端口并解释下你对文件句柄的理解
面试官:服务器最大可以创建多少个tcp连接以及端口并解释下你对文件句柄的理解
129 0
面试官:服务器最大可以创建多少个tcp连接以及端口并解释下你对文件句柄的理解
|
3月前
|
网络协议
【qt】TCP的监听 (设置服务器IP地址和端口号)
【qt】TCP的监听 (设置服务器IP地址和端口号)
207 0