I/O Completion Port DLL
This article explores the IO Completion Port mechanism provided in Windows and compare it with the other mechanisms available to wait for an IO completion
Introduction
The purpose of this article is to explore the IO Completion Port mechanism provided in Windows and compare it with the other mechanisms available to wait for an IO completion.
Large-scale software often needs tens of thousands of socket connections, and if one socket corresponds to one thread, meaning the thread costs the system great expense, IOCP presents an efficient solution to the "one-thread-per-client" bottleneck problem (among others), using only a few processing threads and asynchronous input/output send/receive. The IOCP technology is widely used for different types of high performance servers, such as Apache etc. The lssIocp.dll was something I maintained for two years (IOCP’s storehouse), and I hope my contribution can help somebody.
Background
This is my first article. My English is not very good, but I hoped to obtain everybody's encouragement. Three year’s ago, I needed a high performance server that could maintain 5000 connections at least, and the IOCP was the best solution. I wrote the lssIocp.dll with the help of the Code Project, and now I hope that everybody helps me to further consummate it.
Using the Code
To use lssIocp.dll, you need to include iocpdef.h to your project, and add a function named InitIocp
//int the header file Add: SOCKET m_ListenSocket;
HMODULE m_ModuleIocp;
lpIocpNetInit m_pIocpNetInit;
lpIocpNetListen m_pIocpNetListen;
lpIocpNetSend m_pIocpNetSend;
lpIocpNetRelase m_pIocpNetRelase;
lpIocpNetCloseSocket m_pIocpNetCloseSocket;
lpIocpNetGetStringName m_pIocpNetGetPeerName;
}
CYhTSServerDoc::CYhTSServerDoc()
{
// TODO: add one-time construction code here
m_ModuleIocp=NULL;
m_bListen=false;
m_nListenPort=6000;
m_pIocpNetInit=NULL;
m_pIocpNetCloseSocket=NULL;
m_pIocpNetGetPeerName=NULL;
m_pIocpNetListen=NULL;
m_pIocpNetRelase=NULL;
m_pIocpNetSend=NULL;
}BOOL CYhTSServerDoc::InitIocp()
{
m_ModuleIocp=AfxLoadLibrary(m_strPath+"\\lssIocp.dll");
if(!m_ModuleIocp)
{
AfxMessageBox("lssIocp.dll loader failed");
return FALSE;
}
m_pIocpNetInit =(lpIocpNetInit) GetProcAddress(m_ModuleIocp,
"IocpNetInit");
m_pIocpNetListen =(lpIocpNetListen) GetProcAddress(m_ModuleIocp,
"IocpNetListen");
m_pIocpNetSend =(lpIocpNetSend) GetProcAddress(m_ModuleIocp,
"IocpNetSend");
m_pIocpNetRelase =(lpIocpNetRelase) GetProcAddress(m_ModuleIocp,
"IocpNetRelase");
m_pIocpNetCloseSocket =(lpIocpNetCloseSocket) GetProcAddress(m_ModuleIocp,
"IocpNetCloseSocket");
m_pIocpNetGetPeerName =(lpIocpNetGetStringName) GetProcAddress(m_ModuleIocp,
"IocpNetGetStringName");
if(m_pIocpNetInit==NULL||m_pIocpNetListen==NULL||m_pIocpNetSend==NULL||\
m_pIocpNetRelase==NULL||m_pIocpNetCloseSocket==NULL||
m_pIocpNetGetPeerName==NULL)
{
FreeLibrary(m_ModuleIocp);
m_ModuleIocp=NULL;
AfxMessageBox("init lssIocp.dll failed");
return FALSE;
}
return TRUE;
}int WINAPI NetIocpCallback(IOCP_NET_INFO *pIocp)
{
if(!pIocp)
return 1;
CYhTSServerDoc *pDoc=(CYhTSServerDoc*)pIocp->pOwner;
if(!pDoc)
return 1;
switch(pIocp->cRetType)
{
case IOCP_RET_ACCEPT:
pDoc->OnAccept(pIocp->sParent,pIocp->sClient);
break;
case IOCP_RET_CLOSE:
pDoc->OnClose(pIocp->sParent,pIocp->sClient);
break;
case IOCP_RET_RECEIVE:
pDoc->OnReceive(pIocp->sParent,pIocp->sClient,pIocp->pData,pIocp->nLen);
break;
default:
break;
}
return 0;
}void CYhTSServerDoc::OnCloseDocument()
{
// TODO: Add your specialized code here and/or call the base class
if(m_ModuleIocp)
{
m_pIocpNetRelase();
FreeLibrary(m_ModuleIocp);
m_ModuleIocp=NULL;
}
m_pIocpNetInit=NULL;
m_pIocpNetCloseSocket=NULL;
m_pIocpNetGetPeerName=NULL;
m_pIocpNetListen=NULL;
m_pIocpNetRelase=NULL;
m_pIocpNetSend=NULL;
CDocument::OnCloseDocument();
}