开启服务和中止服务

Start函数用于开启服务数组

1 初始化状态变量服务器

2 建立监听套接字socket

3 加载使用扩展API函数函数

4 建立完成端口对象post

5 创建监听套接字和完成端口对象间的关联ui

6 为监听套接字注册FD_ACCEPT时间this

7 投递AcceptEx IO不够时能够获得通知后建立监听线程spa

BOOL CIOCOPServer::Start(int nPort,int nMaxConnnections,int nMaxFreeBuffers,int nMaxFreeContexts,int nInitialReads) { //检查服务是否启动
    if(m_bServerStarted) return FALSE; //保存参数
    m_nPort = nPort; m_nMaxConnnections = nMaxConnnections; m_nMaxFreeBuffers = nMaxFreeBuffers; m_nMaxFreeContexts = nMaxFreeContexts; m_nInitialReads = nInitialReads; //初始化变量
    m_bServerStarted = TRUE; m_bShutDown = FALSE; //建立监听套接字,绑定到本地端口, 进入监听模式
    m_sListen = ::WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED); SOCKADDR_IN si; si.sin_family = AF_INET; si.sin_port = nPort; si.sin_addr.S_un.S_addr = INADDR_ANY; if(::bind(m_sListen,(sockaddr*)&si,sizeof(si))==SOCKET_ERROR) { m_bServerStarted = FALSE; return FALSE; } ::listen(m_sListen,200); //建立完成端口
    m_hConnection = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); //加载扩展函数AcceptEx
    GUID GuidAcceptEx = WSAID_ACCEPTEX; DWORD dwBytes; WSAIotcl( m_sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &m_lpfnAcceptEx, sizeof(m_lpfnAcceptEx), &dwBytes, NULL, NULL ); //加载GetAcceptExSockaddrs
    GUID GuidAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS; ::WSAIoctl(m_sListen, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuiGetAcceptExSockaddrs, sizeof(GuidGetAcceptExSockaddrs), &m_lpfnAcceptExSockaddrs, sizeof(m_lofnAcceptExSockaddrs), &dwBytes, NULL, NULL); //将监听套接字关联到完成端口
    ::CreateIoCompletionPort((HANDLE)m_sListen,m_hConnection,(DWORD)0,0); //注册FD_ACCEPT事件
 WSAEventSelect(m_sListen,m_hAcceptEvent,FD_ACCEPT); //建立监听线程
    m_hListenThread = ::CreateThread(NULL,0,_ListenThreadProc,this,0,NULL); return TRUE; }

监听线程_ListenThreadProc主要责任:监听套接字投递AcceptEx IO请求。线程

m_hAcceptEvent:当winsock接收到新的链接请求,可是AcceptEx IO,请求来接收这个链接时,就会触发该时间对象。code

m_hRepostEvent:与IO进行交互。

_ListenThreadProc在下面3中状况下投递Accept请求:

1 程序初始化,要先投递几个Accept请求,个数由用户指定

2 处理IO的线程接受到一个客户,使m_hRepostEvent时间受信,_ListenThreadProc线程获得通知后再投递一个Accept请求。

3 程序运行期间,若是投递的Accept请求不够用,用户的链接请求未可以立刻处理,这时候再投递若干个Accept请求。

DWORD WINAPI CIOCPServer::_ListenThreadProc(LPVOID lpParam) { CIOCPServer *pThis = (CIOCPServer*)lpParam; //在监听套接字上投递几个AcceptIO
    CIOCPBuffer *pBuffer; for(int i=0;i<pThis->m_nInitialAccepts;i++) { pBuffer = pThis->AllocateBuffer(BUFFER_SIZE); if(pBuffer==NULL) return -1; pTHis->InsertPendingAccept(pBuffer); pThis->PostAccept(pBuffer); } //构建事件对象数组
    HANDLE hWaitEvents[2+MAX_THREAD]; int nEventCount = 0; hWaitEvents[nEventCount++]=pThis->m_hAcceptEvent; hWaitEvents[nEventCount++]=pThis->m_hRepostEvent; //建立指定数量的工做线程在完成端口上处理IO
    for(i=0;i<MAX_THREAD;i++) { hWaitEvents[nEventCount++]=::CreateThread(NULL,0,_WorkerThreadProc,pThis,0,NULL); } //下面进入无限循环,处理时间对象数组中的事件
    while(TRUE) { int nIndex = ::WSAWaitForMultipleEvents(nEventCount,hWaitEvents,FALSE,60*1000,FALSE); //检查是否要中止服务
        if(pThis->m_bShutDown || nIndex==WSA_WAIT_FAILED) { //关闭全部链接
            pThis->CloseAllConnections(); ::Sleep(0); //关闭监听套接字
            ::closesocket(pThis->m_sListen); pThis->m_sListen=INVALID_SOCKET; ::Sleep(0); //通知全部IO处理线程退出
            for(int i=2;i<MAX_THREAD+2;i++) { ::PostQueuedCompletionStatus(pThis->m_hCompletion,-1,0,NULL); } //等待IO处理线程退出
            ::WaitForMultipleObjects(MAX_THREAD,&hWaitEvents[2],TRUE,5*1000); for(i=2;i<MAX_THREAD+2;i++) { ::CloseHandle(hWaitEvents[i]); } ::CloseHandle(pThis->m_hCompletion); pThis->FreeBuffers(); pThis->FreeContexts(); ::ExitThread(0); } //定时检查全部未返回的AcceptEx IO的链接创建多长时间
        if(nIndex == WSA_WAIT_TIMEOUT) { pBuffer = pThis->m_pPendingAccepts; while(pBuffer!=NULL) { int nSeconds; int nLen = sizeof(nSeconds); //取得链接创建时间
                ::getsockopt(pBuffer->sClient,SOL_SOCKET,SO_CONNECT_TIME,(char*)&nSeconds,&nLen); //若是超过两分钟,就丢弃
                if(nSeconds!=-1 && nSeconds>=2*60) { closesocket(pBuffer->sClient); pBuffer->sClient = INVALIDE_SOCKET; } pBuffer = pBuffer->pNext; } } else { nIndex = nIndex-WAIT_OBJECT_0; WSANETWORKEVENTS ne; int nLimit=0; if(nIndex==0)//m_hAcceptEvent时间对象受信,说明投递的Accept请求不够,须要增长
 { ::WSAEnumNetworkEvents(pThis->m_sListen,hWaitEvents[nIndex],&ne); if(ne.lNetworkEvents & FD_ACCEPT) { nLimit = 50; } } else if(nIndex==1)//m_hRepostEvent事件对象受信,说明处理IO的线程接受到新的客户
 { nLimit = InterlockedExchange(&pThis->m_nRepostCount,0); } else if(nIndex>1)//IO服务线程退出,说明有错误发生,关闭服务器
 { pThis->m_bShutDown = TRUE; continue; } //投递nLimit个AcceptEx IO 请求
            int i=0; while(i++ < nLimit && pThis->m_nPendingAcceptCount < pThis->m_nMaxAccepts) { pBuffer = pThis->AllocateBuffer(BUFFER_SIZE); if(pBuffer!=NULL) { pThis->InsertPendingAccept(pBuffer); pThis->PostAccept(pBuffer); } } } } return 0; }

 

 3 中止服务函数ShutDown

void CIOCPServer::ShutDown() { if(!m_bServerStarted) return; //通知监听线程,立刻中止服务
    m_bShutDown = TRUE; ::SetEvent(m_hAcceptEvent); //等待监听线程退出
 ::WaitForSingleObject(m_hListenThread,INFINITE); ::CloseHandle(m_hListenThread); m_hListenThread = NUll; m_bServerStarted = FALSE; }
相关文章
相关标签/搜索