博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
开启服务和停止服务
阅读量:6904 次
发布时间:2019-06-27

本文共 5755 字,大约阅读时间需要 19 分钟。

Start函数用于开启服务

1 初始化状态变量

2 创建监听套接字

3 加载使用扩展API函数

4 创建完成端口对象

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

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

7 投递AcceptEx IO不够时可以得到通知后创建监听线程

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,请求来接收这个连接时,就会触发该时间对象。

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
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
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
m_hCompletion,-1,0,NULL); } //等待IO处理线程退出 ::WaitForMultipleObjects(MAX_THREAD,&hWaitEvents[2],TRUE,5*1000); for(i=2;i
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;}

 

 

转载地址:http://peldl.baihongyu.com/

你可能感兴趣的文章
iPhone 物理尺寸与分辨率
查看>>
win10系统下cmd输入一下安装的软件命令提示拒绝访问解决办法
查看>>
OpenJudge/Poj 1004 Financial Management
查看>>
面向服务(接口)开发过程中常用的实体类数据复制解决方案
查看>>
Scala 学习笔记之函数(3)
查看>>
Fiddler (二) Script 用法
查看>>
[转载] 信息系统项目管理师考试习题——整体管理
查看>>
LC 425 word squares
查看>>
Web框架之Django_08 重要组件(form组件、cookie和session组件)
查看>>
HDU 6103
查看>>
zookeeper 实现分布式锁
查看>>
sql server 数据修改不了的设计
查看>>
Reinforcement Learning by Sutton 第三章习题答案
查看>>
mysql tinyint
查看>>
UNIX网络编程——getsockname和getpeername函数
查看>>
Bad Request - Request Too Long
查看>>
sqlist
查看>>
全员利润管理实践(3)-生产的利润管理
查看>>
[转帖]c头文件(.h)的作用
查看>>
http请求的request和response
查看>>