• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 298  文章 - 377  trackbacks - 0
            <2007年8月>
            2930311234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678

            常用鏈接

            留言簿(34)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊(cè)

            收藏夾

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            Windows2000之后的版本提供的完成端口的應(yīng)用,這使得開發(fā)服務(wù)器端程序變得更簡(jiǎn)便了,我們不用再為每一個(gè)連接而去維護(hù)令人厭煩的線程池。Windows提供的完成端口封裝了一切繁瑣的工作,我們唯一要做的就是對(duì)完成端口的應(yīng)用。

            // 創(chuàng)建監(jiān)聽套接字
            SOCKET m_socListen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
            // 設(shè)置異步連接標(biāo)志
            if (WSAAsyncSelect(m_socListen, m_hMainWnd, UM_SOCKETEVENT, FD_ACCEPT)==SOCKET_ERROR) return SOCKET_ERROR;
            // 初始化完成端口
            IOCP_Initialize();
            /*
            IOCP_Initialize()
            {
            SYSTEM_INFO systeminfo;
            DWORD dwThreadID;
            m_hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
            if( m_hCompletionPort == NULL 
            {
            TRACE(_T("CreateIoCompletionPort failed with error: %d\n", GetLastError());
            return -1;
            }
            m_bStopIOCP=FALSE;
            m_hThreadIOCP=NULL;
            GetSystemInfo( &systeminfo ;
            for(DWORD i=0; i<systeminfo.dwNumberOfProcessors; i++)
            {
            m_hThreadIOCP = CreateThread( NULL, // Security
            0, // Stack size - use default
            (LPTHREAD_START_ROUTINE)IOCP_ThreadPoolFunc, // Thread function entry point
            (void*) this, // Param for thread
            0, // Init flag
            &dwThreadID); // Thread ID
                    if (m_hThreadIOCP!=NULL) 
            {
            InterlockedIncrement((LPLONG)&m_nWorkerCnt);
            CloseHandle(m_hThreadIOCP);
            }
            }
            }

            IOCP_ThreadPoolFunc (LPVOID lpParam)    
            {
            ASSERT(lpParam);
            CIOCPServer* pThis = reinterpret_cast<CIOCPServer*>(lpParam);
            HANDLE hCompletionPort = pThis->m_hCompletionPort;

            DWORD dwBytesTransferred=0; // Bytes transferred in the Completion packet
            DWORD dwIoType=0; // The operation type of completion packet
            DWORD dwFlags=0;

            LPPERHANDLEDATA lpPerHandleData;
            LPPERIOOPERATIONDATA lpPerIoData;

            while(!pThis->IsIOCPstopped())
            {
            BOOL bIoRet = FALSE;
            if((bIoRet = GetQueuedCompletionStatus(
            hCompletionPort,
            &dwBytesTransferred,
            (LPDWORD) &lpPerHandleData,
            (LPOVERLAPPED*)&lpPerIoData,
            INFINITE))==0)
            {
            DWORD dwError=GetLastError();
            if(dwError==ERROR_NETNAME_DELETED)
            {
            // 服務(wù)器主動(dòng)關(guān)閉套接字
            if(lpPerIoData) { pThis->FreePerIoData(lpPerIoData); lpPerIoData=NULL; };
            /*
            FreePerIoData(PERIOOPERATIONDATA* lpPerIoData)
            {
            if(lpPerIoData->m_pOutBuf)
            {
            delete[] lpPerIoData->m_pOutBuf;
            lpPerIoData->m_pOutBuf=NULL;
            }
            delete(lpPerIoData);
            lpPerIoData=NULL;
            }
            */
            continue;
            }

            TRACE("GetQueuedCompletionStatus failed with error %d\n", dwError);
            InterlockedDecrement(&pThis->m_nWorkerCnt);
            return 0;
            }

            if(lpPerIoData==NULL && lpPerHandleData==NULL)
            {
            // 服務(wù)器關(guān)閉完成端口
            InterlockedDecrement(&pThis->m_nWorkerCnt);
            return 0;
            }

            // First check to see if an error has occured on the socket and if so
            // then close the socket and cleanup the SOCKET_INFORMATION structure
            // associated with the socket.
            if ((dwBytesTransferred==0) && ((lpPerIoData->m_ioType==IORead)||(lpPerIoData->m_ioType==IOWrite)))
            {
            pThis->RemoveStaleClient(lpPerHandleData->m_Socket,FALSE);
            if(lpPerIoData) { pThis->FreePerIoData(lpPerIoData); lpPerIoData=NULL;
            continue;
            }

            if( lpPerHandleData!=NULL && lpPerIoData!=NULL 
            {
            BOOL bRet = pThis->IOCP_ProcessIOMessage(lpPerHandleData, lpPerIoData, dwBytesTransferred);

            // Before Every PostQueuedCompletionStatus() call we allocate a memory for PerIoData.
            // And Before every WSASend() and WSARecv() call we also allocate such a block of memory.
            // So After handling every QueuedCompletion Packet, we Free this block if it's not useful.

            /*
            enum IOType { IOIdle,IORead,IOWrite,IOInitialize };
            IOCP_ProcessIOMessage(PERHANDLEDATA* pContext, PERIOOPERATIONDATA* pPerIoData, DWORD dwSize = 0)
            {
            int nRet = 0; 
            IOType clientIO = pPerIoData->m_ioType; 

            if( clientIO == IOInitialize)
            nRet = IOCP_OnClientInitializing(pContext, pPerIoData, dwSize);
            else if( clientIO == IORead)
            nRet = IOCP_OnClientReading(pContext, pPerIoData, dwSize);
            else if( clientIO == IOWrite)
            nRet = IOCP_OnClientWriting(pContext, pPerIoData, dwSize);
            }

            IOCP_OnClientInitializing(PERHANDLEDATA* lpContext, PERIOOPERATIONDATA* lpPerIoData, DWORD dwIoSize)
            {
            // launch another recv operation.
            DWORD dwBytesTransferred=0;
            PERIOOPERATIONDATA*  lpPerIoDataResv = new PERIOOPERATIONDATA;
            memset(lpPerIoDataResv,0,sizeof(PERIOOPERATIONDATA));
            lpPerIoDataResv->m_ioType = IORead;
            lpPerIoDataResv->m_wsaDataBuf.buf = lpPerIoDataResv->m_Buffer;
            lpPerIoDataResv->m_wsaDataBuf.len = sizeof(lpPerIoDataResv->m_Buffer);

            ULONG ulFlags = 0;
            int nRet = WSARecv( lpContext->m_Socket,
            &lpPerIoDataResv->m_wsaDataBuf,
            1,
            &dwBytesTransferred,
            &ulFlags,
            (LPWSAOVERLAPPED)&lpPerIoDataResv->Overlapped,
            NULL);

            if ( nRet == SOCKET_ERROR 
            {
            DWORD dwError = WSAGetLastError();
            if( dwError != WSA_IO_PENDING) 
            {
            RemoveStaleClient( lpContext->m_Socket, FALSE ;
            return NC_E_IOCP_INITIALIZE|dwError;
            }
            }
            }

            IOCP_OnClientReading(PERHANDLEDATA* pContext, PERIOOPERATIONDATA* pPerIoData, DWORD dwSize)
            {
            // make sure to issue a read after this
            // pContext->m_wsaInBuffer.buf/*==pContext->m_byInBuffer*/是該套接字的緩沖區(qū),
            // 如果該緩沖區(qū)中有數(shù)據(jù)(pContext->m_wsaInBuffer.len!=0時(shí)),
            // 則說(shuō)明上次收到了一個(gè)請(qǐng)求包的一部分?jǐn)?shù)據(jù),把這次的數(shù)據(jù)繼續(xù)放入
            memmove(pContext->m_wsaInBuffer.buf+pContext->m_wsaInBuffer.len,pPerIoData->m_wsaDataBuf.buf,dwSize);
            pContext->m_wsaInBuffer.len+=dwSize;
            HandleRequest(pContext);

            // launch another recv operation.
            DWORD dwBytesTransferred=0;
            PERIOOPERATIONDATA*  lpPerIoDataResv = new PERIOOPERATIONDATA;
            memset(lpPerIoDataResv,0,sizeof(PERIOOPERATIONDATA));
            lpPerIoDataResv->m_ioType = IORead;
            lpPerIoDataResv->m_wsaDataBuf.buf = lpPerIoDataResv->m_Buffer;
            lpPerIoDataResv->m_wsaDataBuf.len = sizeof(lpPerIoDataResv->m_Buffer);

            int nRet = WSARecv( pContext->m_Socket,
            &lpPerIoDataResv->m_wsaDataBuf,
            1,
            &dwBytesTransferred,
            &ulFlags,
            (LPWSAOVERLAPPED)&lpPerIoDataResv->Overlapped,
            NULL);

            if ( nRet == SOCKET_ERROR 
            {
            DWORD dwError = WSAGetLastError();
            if( dwError != WSA_IO_PENDING && dwError != WSAENOTSOCK) 
            {
            RemoveStaleClient( pContext->m_Socket, FALSE ;
            return NC_E_IOCP_READ|dwError;
            }
            }
            }

            IOCP_OnClientWriting(PERHANDLEDATA* pContext, PERIOOPERATIONDATA* pPerIoData, DWORD dwSize)
            {
            // SendPacket調(diào)用異步發(fā)送數(shù)據(jù),當(dāng)數(shù)據(jù)發(fā)送完成后,將來(lái)此處
            }

            SendPacket(PERHANDLEDATA* pContext,BYTE* sendbuf,DWORD dwLength)
            {
            // 發(fā)送數(shù)據(jù)代碼斷如下:
            PERIOOPERATIONDATA*  lpPerIoDataRPP = new PERIOOPERATIONDATA;
            memset(lpPerIoDataRPP,0,sizeof(PERIOOPERATIONDATA));
            lpPerIoDataRPP->m_ioType = IOWrite;
            memset(lpPerIoDataRPP->m_Buffer,0,sizeof(lpPerIoDataRPP->m_Buffer));
            lpPerIoDataRPP->m_pOutBuf=new BYTE[dwLength];
            memmove(lpPerIoDataRPP->m_pOutBuf,(BYTE*)sendbuf,dwLength);
            lpPerIoDataRPP->m_wsaDataBuf.buf = (char*)lpPerIoDataRPP->m_pOutBuf;
            lpPerIoDataRPP->m_wsaDataBuf.len = dwLength;
            int nRetVal = WSASend(pContext->m_Socket,
            &lpPerIoDataRPP->m_wsaDataBuf,
            1,
            &lpPerIoDataRPP->m_wsaDataBuf.len, 
            0,
            &(lpPerIoDataRPP->Overlapped), 
            NULL);
            if ( nRetVal == SOCKET_ERROR 
            {
            DWORD dwError=WSAGetLastError();
            if( dwError != WSA_IO_PENDING  
            {
            RemoveStaleClient( socClient, FALSE ;
            return NC_E_TCP_SENDRESPONSE|dwError;
            }
            }
            // 發(fā)送完畢
            }
            */

            if( lpPerIoData  { pThis->FreePerIoData(lpPerIoData); lpPerIoData=NULL; }
            }
            }

            InterlockedDecrement(&pThis->m_nWorkerCnt);

            return 0;
            }
            */

            // 綁定服務(wù)器地址
            SOCKADDR_IN saiServer;
            saiServer.sin_family = AF_INET;
            saiServer.sin_port   = htons(NC_S_PORT_LISTEN);
            saiServer.sin_addr.S_un.S_addr = inet_addr(pszLocalAddr);
            if(bind(m_socListen,(SOCKADDR*)&saiServer,sizeof(saiServer))==SOCKET_ERROR) return NC_E_TCP_LISTEN|WSAGetLastError();
            // 開始偵聽
            if(listen(m_socListen,SOMAXCONN)==SOCKET_ERROR) return NC_E_TCP_LISTEN|WSAGetLastError();


            case FD_ACCEPT: IOCP_OnAccept();break;

            IOCP_OnAccept()
            {
            SOCKET socClient;
            SOCKADDR_IN saiRemote;
            int nLen = sizeof(saiRemote);
            if( (socClient=accept(m_socListen,(LPSOCKADDR)&saiRemote,&nLen))==SOCKET_ERROR) return NC_E_TCP_ONACCEPT|WSAGetLastError();

            // 1、設(shè)置套接字選項(xiàng)
            BOOL bOpt = true;
            int nRcvBuf = BUFSIZE_NC_S_RCVBUF;
            int nSndBuf = BUFSIZE_NC_S_SNDBUF;
            int nErr = 0;
            int nTimeout = 10*1000;
            nErr = setsockopt(socClient, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeout, sizeof(nTimeout));
            nErr = setsockopt(socClient, SOL_SOCKET, SO_RCVBUF, (const char*)&nRcvBuf,sizeof(nRcvBuf));
            nErr = setsockopt(socClient, SOL_SOCKET, SO_SNDBUF, (const char*)&nSndBuf,sizeof(nSndBuf));

            // 2、將該套接字關(guān)聯(lián)完成端口
            // Create the Client context to be associted with the completion port
            PERHANDLEDATA* pContext = IOCP_AllocatePerHandleContext();

            /*
            typedef struct tagPerHandleData
            {
            SOCKET m_Socket;
            DWORD  m_dwStatus;

            // Input Elements for Winsock
            WSABUF m_wsaInBuffer;
            BYTE   m_byInBuffer[DATA_BUFSIZE];    

            // Output elements for Winsock
            WSABUF m_wsaOutBuffer;

            }PERHANDLEDATA, *LPPERHANDLEDATA;

            IOCP_AllocatePerHandleContext()
            {
            PERHANDLEDATA* pContext = NULL;
            if (!m_listFreePool.IsEmpty())
            {
            pContext = m_listFreePool.RemoveHead();
            }
            else
            {
            pContext = new PERHANDLEDATA;
            memset(pContext,0,sizeof(PERHANDLEDATA));
            }
            if(pContext) memset(pContext,0,sizeof(PERHANDLEDATA));
            return pContext;
            }
            */

            pContext->m_Socket = socClient;
            pContext->m_wsaInBuffer.buf = (char*)pContext->m_byInBuffer;
            pContext->m_wsaInBuffer.len = 0;

            // 保存PerHandleContext的列表
            PERHANDLEDATA* pContextTmp = NULL;
            if (m_listContexts.Lookup(socClient, pContextTmp))
            RemoveStaleClient(socClient,TRUE);
            else
            m_listContexts.SetAt(nSocket, pContext);

            /*
            RemoveStaleClient(SOCKET s,BOOL bGraceful)
            {
            PERHANDLEDATA* pContext=NULL;
            m_listContexts.Lookup(nSocket,pContext);
            if(pContext==NULL) return;

            LINGER lingerStruct;
            if ( bGraceful  
            {
            lingerStruct.l_onoff = 1;
            lingerStruct.l_linger= 30; // linger for 30 seconds, 0 for abort
            }
            else
            {
            lingerStruct.l_onoff = 0;
            lingerStruct.l_linger= 0; // ignored
            }
            setsockopt( pContext->m_Socket, SOL_SOCKET, SO_LINGER, (char *)&lingerStruct, sizeof(lingerStruct) ;
            while (!HasOverlappedIoCompleted((LPOVERLAPPED)pContext)) Sleep(0);
            MoveToFreePool(nSocket);

            //
            //MoveToFreePool(SOCKET s)
            //{
            // PERHANDLEDATA* pContext = NULL;
            //
            //    // Free context structures
            // if (m_listContexts.Lookup(nSocket, pContext)) 
            // {
            // m_listFreePool.AddTail(pContext);
            // m_listContexts.RemoveKey(nSocket);
            // }
            //}
            //

            // Free context structures
            // Now close the socket handle.  This will do an abortive or  graceful close, as requested.  
            closesocket( pContext->m_Socket ;
            pContext->m_Socket = INVALID_SOCKET;
            }
            */

            // Associate the new socket with a completion port.
            if(IOCP_AssociateSocketWithPort(pContext->m_Socket, m_hCompletionPort, (DWORD)pContext)!=0)
            {
                    RemoveStaleClient(socClient,TRUE);
            DWORD dwError=GetLastError();
            return NC_E_TCP_ONACCEPT;
            }
            /*
            IOCP_AssociateSocketWithPort(SOCKET socket, HANDLE hCompletionPort, DWORD dwCompletionKey)
            {
            HANDLE h=CreateIoCompletionPort((HANDLE) socket, hCompletionPort, dwCompletionKey, 0);
            return (h==hCompletionPort)?0:-1;
            }
            */

            // 3、該套接字的完成端口初始化
            // Trigger first IO Completion Request
            // Otherwise the Worker thread will remain blocked waiting for GetQueuedCompletionStatus...
            // The first message that gets queued up is ClientIoInitializing - see ThreadPoolFunc 
            /*
            typedef struct tagPerIoOperationData
            {
            OVERLAPPED Overlapped;
            IOType m_ioType;

            BYTE*  m_pOutBuf;
            WSABUF m_wsaDataBuf;
            CHAR   m_Buffer[DATA_BUFSIZE];

            } PERIOOPERATIONDATA,*LPPERIOOPERATIONDATA;
            */
            PERIOOPERATIONDATA*  lpPerIoData = NULL;
            lpPerIoData = new PERIOOPERATIONDATA;
            memset(lpPerIoData,0,sizeof(PERIOOPERATIONDATA));
            lpPerIoData->m_ioType = IOInitialize;
            lpPerIoData->m_wsaDataBuf.len = sizeof(lpPerIoData->m_Buffer);
            lpPerIoData->m_wsaDataBuf.buf = lpPerIoData->m_Buffer;
            BOOL bSuccess = PostQueuedCompletionStatus(m_hCompletionPort, 0, (DWORD) pContext, &lpPerIoData->Overlapped);
            if(!bSuccess) return NC_E_TCP_ONACCEPT|WSAGetLastError();
            return socClient;
            }

            // 結(jié)束的時(shí)候需要關(guān)閉完成端口
            CloseListenSocket()
            {
            // 關(guān)閉每個(gè)連接, 從列表中移去關(guān)鍵字
            PERHANDLEDATA* pContext = NULL;
            int nSocket=0;
            do
            {
            POSITION pos  = m_listContexts.GetStartPosition();
            if (pos)
            {
            m_listContexts.GetNextAssoc(pos, nSocket, pContext);
            RemoveStaleClient(nSocket, FALSE);
            }
            }while (!m_listContexts.IsEmpty());

            // 釋放每個(gè)連接相關(guān)的分配內(nèi)存
            while (!m_listFreePool.IsEmpty())
            {
            PERHANDLEDATA* pContext = m_listFreePool.RemoveTail();
            delete pContext;
            }

            m_bStopIOCP=TRUE;

            if(m_bIOCPInitialed==TRUE)
            {
            IOCP_CloseCompletionPort();
            /*
            IOCP_CloseCompletionPort()
            {
            while (m_nWorkerCnt)
            {
            PostQueuedCompletionStatus(m_hCompletionPort, 0, (DWORD) NULL, NULL);
            Sleep(1000);
            }
            // Close the CompletionPort and stop any more requests
            CloseHandle(m_hCompletionPort);
            m_bIOCPInitialed=FALSE;
            m_bStopIOCP=TRUE;
            }
            } */
            }

            if(m_socListen!=0)
            {
            closesocket(m_socListen);
            m_socListen=0;
            }
            return 0;
            }
            posted on 2007-08-17 13:10 聶文龍 閱讀(835) 評(píng)論(0)  編輯 收藏 引用 所屬分類: net work
            中文精品久久久久人妻不卡| 日本久久久久久中文字幕| 97精品依人久久久大香线蕉97| 亚洲精品乱码久久久久久久久久久久 | 亚洲狠狠综合久久| 久久毛片一区二区| 久久综合丝袜日本网| 久久精品免费全国观看国产| 久久久国产精品福利免费| 亚洲精品乱码久久久久久蜜桃 | 99久久精品国产一区二区| 蜜桃麻豆www久久| 精品久久久久久国产| 久久国产精品偷99| 久久精品aⅴ无码中文字字幕重口 久久精品a亚洲国产v高清不卡 | 久久国产精品无码网站| 新狼窝色AV性久久久久久| 久久93精品国产91久久综合| 久久久久久亚洲AV无码专区| 久久综合偷偷噜噜噜色| 久久久久亚洲精品无码网址| 东京热TOKYO综合久久精品 | 久久91精品综合国产首页| 久久精品国产亚洲AV嫖农村妇女 | 国产午夜久久影院| 午夜精品久久久久久99热| 亚洲午夜福利精品久久| 久久久久国产精品嫩草影院| 波多野结衣中文字幕久久| 久久人人爽人人爽人人AV | 久久久无码精品亚洲日韩按摩 | 久久综合九色综合网站| 漂亮人妻被中出中文字幕久久| 久久人人爽人人爽AV片| 亚洲国产成人久久精品动漫| 99久久精品日本一区二区免费| 久久久老熟女一区二区三区| 午夜精品久久久久久中宇| 亚洲成色WWW久久网站| 欧美一区二区三区久久综合| 久久综合噜噜激激的五月天|