?? iocpmodesvr.cpp
字號:
// IocpModeSvr.cpp: implementation of the CIocpModeSvr class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "IocpModeSvr.h"
#include <fstream.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#pragma warning(disable:4800)
DWORD WINAPI ServerWorkerProc(LPVOID lParam)
{
CIocpModeSvr* pSvr=(CIocpModeSvr*)lParam;
HANDLE CompletionPort=pSvr->CompletionPort;
DWORD ByteTransferred;
LPPER_HANDLE_DATA PerHandleData;
PPER_IO_OPERATION_DATA PerIoData;
DWORD RecvByte;
while(true)
{
bool bSuccess=GetQueuedCompletionStatus(CompletionPort,
&ByteTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED* )&PerIoData,
INFINITE);
//退出信號到達,退出線程
if(ByteTransferred==-1 && PerIoData==NULL)
{
return 1L;
}
//客戶機已經斷開連接或者連接出現錯誤
if(ByteTransferred==0 &&
(PerIoData->OperType==RECV_POSTED || PerIoData->OperType==SEND_POSTED))
{
//將該客戶端數據刪除
int arrSize=0;
bool bFind=false;
::EnterCriticalSection(&pSvr->cInfoSection);
while(arrSize<pSvr->ClientInfo.GetSize())
{
PER_HANDLE_DATA pPerHandleData=pSvr->ClientInfo.GetAt(arrSize);
if((pPerHandleData.IpAddr==PerHandleData->IpAddr) &&
(pPerHandleData.sClient==PerHandleData->sClient))
{
bFind=true;
pSvr->ClientInfo.RemoveAt(arrSize);
break;
}
arrSize++;
}
::LeaveCriticalSection(&pSvr->cInfoSection);
if(bFind)
{
//記錄退出日志
CString LogStr;
in_addr in_A;
in_A.S_un.S_addr=PerHandleData->IpAddr;
LogStr.Format("Ip: %s,Socket : %d Disconneted",inet_ntoa(in_A),PerHandleData->sClient);
pSvr->WriteLogString(LogStr);
TRACE("\nSocket : %d Disconneted",PerHandleData->sClient);
//調用回調函數,通知上層該客戶端已經斷開
pSvr->m_pProcessRecvData(PerHandleData->IpAddr,
PerHandleData->sClient,
NULL,
0);
//關閉套接口
closesocket(PerHandleData->sClient);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
}
continue;
}
//為讀操作完成,處理數據
if(PerIoData->OperType==RECV_POSTED)
{
//調用回調函數,處理數據
pSvr->m_pProcessRecvData(PerHandleData->IpAddr,
PerHandleData->sClient,
PerIoData->RecvBuf,
ByteTransferred);
//將源數據置空
memset(PerIoData->RecvBuf,0,BUFFER_SIZE);
ByteTransferred=0;
//重置IO操作數據
unsigned long Flag=0;
ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED));
PerIoData->RecvDataBuf.buf=PerIoData->RecvBuf;
PerIoData->RecvDataBuf.len=BUFFER_SIZE;
PerIoData->OperType=RECV_POSTED;
//提交另一個Recv請求
WSARecv(PerHandleData->sClient,
&(PerIoData->RecvDataBuf),
1,
&RecvByte,
&Flag,
&(PerIoData->OverLapped),
NULL);
}
//發送完成,置空緩沖區,釋放緩沖區
if(PerIoData->OperType==SEND_POSTED)
{
memset(PerIoData,0,sizeof(PER_IO_OPERATION_DATA));
GlobalFree(PerIoData);
ByteTransferred=0;
}
}
return 0L;
}
DWORD WINAPI ListenProc(LPVOID lParam)
{
CIocpModeSvr* pSvr=(CIocpModeSvr*)lParam;
SOCKET Accept;
while(true)
{
//接收客戶的請求
Accept=WSAAccept(pSvr->ListenSocket,NULL,NULL,NULL,0);
//申請新的句柄操作數據
LPPER_HANDLE_DATA PerHandleData=(LPPER_HANDLE_DATA) \
GlobalAlloc(GPTR,
sizeof(PER_HANDLE_DATA)
);
//取得客戶端信息
sockaddr soad;
sockaddr_in in;
int len=sizeof(soad);
if(getpeername(Accept,&soad,&len)==SOCKET_ERROR)
{
CString LogStr;
LogStr.Format("getpeername() faild : %d",GetLastError());
pSvr->WriteLogString(LogStr);
}
else{
memcpy(&in,&soad,sizeof(sockaddr));
}
//句柄數據
PerHandleData->sClient=Accept;
PerHandleData->IpAddr=in.sin_addr.S_un.S_addr;
//存儲客戶信息
::EnterCriticalSection(&pSvr->cInfoSection);
pSvr->ClientInfo.Add(*PerHandleData);
::LeaveCriticalSection(&pSvr->cInfoSection);
//轉儲信息
CString LogStr;
LogStr.Format("UserIP: %s ,Socket : %d Connected!",inet_ntoa(in.sin_addr),Accept);
pSvr->WriteLogString(LogStr);
TRACE("\nUserIP: %s ,Socket : %d Connected!",inet_ntoa(in.sin_addr),Accept);
//關聯客戶端口到完成端口,句柄數據在此時被綁定到完成端口
CreateIoCompletionPort((HANDLE)Accept,
pSvr->CompletionPort,
(DWORD)PerHandleData,
0);
//Io操作數據標志
PPER_IO_OPERATION_DATA PerIoData=(PPER_IO_OPERATION_DATA) \
GlobalAlloc(GPTR,
sizeof(PER_IO_OPERATION_DATA));
unsigned long Flag=0;
DWORD RecvByte;
ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED));
PerIoData->RecvDataBuf.buf=PerIoData->RecvBuf;
PerIoData->RecvDataBuf.len=BUFFER_SIZE;
PerIoData->OperType=RECV_POSTED;
//提交首個接收數據請求
//這時
//如果客戶端斷開連接
//則也可以以接收數據時得到通知
WSARecv(PerHandleData->sClient,
&(PerIoData->RecvDataBuf),
1,
&RecvByte,
&Flag,
&(PerIoData->OverLapped),
NULL);
}
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CIocpModeSvr::CIocpModeSvr()
{
IsStart=false;
}
CIocpModeSvr::~CIocpModeSvr()
{
}
bool CIocpModeSvr::SendMsg(LPCTSTR TargetIp,char * pData,unsigned long Length)
{
if(TargetIp=="" || pData==NULL || Length==0 || !IsStart)
return false;
bool bFind=false;
PER_HANDLE_DATA pPerHandleData;
memset(&pPerHandleData,0,sizeof(PER_HANDLE_DATA));
unsigned long tIp=inet_addr(TargetIp);
//在表中查找該客戶端數據并發送數據
::EnterCriticalSection(&cInfoSection);
int arrSize=0;
while(arrSize<ClientInfo.GetSize())
{
pPerHandleData=ClientInfo.GetAt(arrSize);
if((pPerHandleData.IpAddr==tIp))
{
bFind=true;
break;
}
arrSize++;
}
::LeaveCriticalSection(&cInfoSection);
//找到該客戶端,可以提交發送數據請求了
if(bFind)
{
return SendMsg(pPerHandleData.sClient,pData,Length);
}
else
{
CString LogStr;
pData[Length]='\0';
LogStr.Format("試圖發送數據到沒有連接的客戶端:%s數據:%s",TargetIp,pData);
WriteLogString(LogStr);
return false;
}
return false;
}
//提交發送消息請求,
//如果提交發送消息失敗,
//則將導致在工作線程里將目標客戶端的連接切斷
bool CIocpModeSvr::SendMsg(SOCKET sClient,char * pData,unsigned long Length)
{
if(sClient==INVALID_SOCKET || pData==NULL || Length==0 || !IsStart)return false;
//申請操作鍵
PPER_IO_OPERATION_DATA PerIoData=(PPER_IO_OPERATION_DATA) \
GlobalAlloc(GPTR,
sizeof(PER_IO_OPERATION_DATA));
//準備緩沖
unsigned long Flag=0;
DWORD SendByte;
ZeroMemory(&(PerIoData->OverLapped),sizeof(OVERLAPPED));
memcpy(PerIoData->SendBuf,pData,Length);
PerIoData->SendDataBuf.buf=PerIoData->SendBuf;
PerIoData->SendDataBuf.len=Length;
PerIoData->OperType=SEND_POSTED;
int bRet=WSASend(sClient,
&(PerIoData->SendDataBuf),
1,
&SendByte,
Flag,
&(PerIoData->OverLapped),
NULL);
if(bRet==SOCKET_ERROR && GetLastError()!=WSA_IO_PENDING)
{
CString LogStr;
LogStr.Format("WSASend With Error : %d",GetLastError());
WriteLogString(LogStr);
return false;
}
else return true;
return false;
}
bool CIocpModeSvr::SendMsgToAll(char * pData,unsigned long Length)
{
if(pData==NULL || Length==0 || !IsStart)return false;
::EnterCriticalSection(&cInfoSection);
int arrSize=0;
PER_HANDLE_DATA pPerHandleData;
while(arrSize<ClientInfo.GetSize())
{
memset(&pPerHandleData,0,sizeof(PER_HANDLE_DATA));
pPerHandleData=ClientInfo.GetAt(arrSize);
SendMsg(pPerHandleData.sClient,pData,Length);
arrSize++;
}
::LeaveCriticalSection(&cInfoSection);
return true;
}
bool CIocpModeSvr::SendMsgToOther(LPCTSTR ExceptIp,char *pData,unsigned long Length)
{
if(ExceptIp=="" || pData==NULL || Length==0 || !IsStart)return false;
::EnterCriticalSection(&cInfoSection);
int arrSize=0;
PER_HANDLE_DATA pPerHandleData;
while(arrSize<ClientInfo.GetSize())
{
memset(&pPerHandleData,0,sizeof(PER_HANDLE_DATA));
pPerHandleData=ClientInfo.GetAt(arrSize);
if(pPerHandleData.IpAddr!=inet_addr(ExceptIp))
SendMsg(pPerHandleData.sClient,pData,Length);
arrSize++;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -