簡化后的CNetClient類圖:
本次是分享下整體設計思想,不研究細節網絡實現。
CNetClient用戶客戶端的網絡處理。主要功能需求如下:
*能接收遠端數據
*能把接收到的數據送到上層處理
*能向遠端發送數據
**發送和接收都是異步
**CNetClient本身是一個底層服務,對上層是異步的
針對上述需求GodofMoney實現的非常簡單:
針對發送和接收單獨開線程,回調OnRecvProc OnSend
和上層數據交互通過兩個隊列完成,一個發送隊列,一個接收隊列。
上層將需要發送的數據放到發送隊列,底層將接收到的數據調用上層給的處理函數處理后push出去
先這么多吧,以后還會繼續分析,,,
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////NetClient.h///////////////////////
//! NetClient.h: interface for the CNetClient class.
//!發送接收原始網絡包執行類
#if !defined(AFX_NETCLIENT_H__CF62B9AC_911A_4CE6_81B2_55CB2588A42E__INCLUDED_)
#define AFX_NETCLIENT_H__CF62B9AC_911A_4CE6_81B2_55CB2588A42E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif //! _MSC_VER > 1000
#define SERVERPORT 10012
#define BUFFER_SIZE 4096
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#pragma once
/*******************************************************************************************
*******************************************************************************************/
//!錯誤定義:套接字上的數據操作正忙
#define CLIENT_FUNERROR 0x100
//!TCP winsock連接類
class CClientSocket
{
friend class CNetClient;
public:
CClientSocket();
CClientSocket(bool & bSuccess,int iSockType,char * szSvrAddr,unsigned short iSvrPort)
{
bSuccess=false;
bSuccess=CreateSocket(iSockType);
bSuccess=ConnectSocket(szSvrAddr,iSvrPort);
}
virtual ~CClientSocket();
public:
//!釋放資源
void UnInit();
//!winsocket處理
bool CreateSocket(int iSockType){
return CreateSocket(&m_Socket,iSockType);
}
bool BindSocket(char *szHostAddr,unsigned short iHostPort){
return BindSocket(m_Socket,szHostAddr,iHostPort);
}
bool ShutDownSocket(){
return ShutDownSocket(m_Socket);
}
bool CloseSocekt(){
return CloseSocket(m_Socket);
}
bool ConnectSocket(char * szDestAddr,unsigned short iDestPort);
//!發送與接收數據
/*
*char * data 數據指針
*DWORD len 數據長度
*DWORD *retlen 處理長度
*DWORD time 等待時間
*返回:true為成功,否則為失敗
*/
bool SendMsg(char * data,DWORD len,DWORD *retlen,DWORD time);
bool RecvMsg(char * data,DWORD len,DWORD *retlen,DWORD time);
char m_szDestAddr[255];
BOOL m_bEnData;
protected:
bool CreateSocket(SOCKET *pNewSocket,int iSockType);
bool BindSocket(SOCKET BindSocket,char *szHostAddr,unsigned short iHostPort);
bool ShutDownSocket(SOCKET nowSocket);
bool CloseSocket(SOCKET nowSocket);
bool SendDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time);
bool RecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time);
private:
bool SendData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time);
bool RecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time);
private:
SOCKET m_Socket;
WSAEVENT m_hExitEvent;
struct sockaddr_in inAddr;
};
/*******************************************************************************
消息隊列類:用于存儲消息隊列,即待發送的消息的集合,或者是接收過待處理的集合
*******************************************************************************/
template <class T> class Queue;
//!鏈式隊列結點定義
template <class T> class QueueNode
{
friend class Queue<T>;
private:
T data;//!數據域
QueueNode<T> *link;//!鏈域
QueueNode(T d,QueueNode *l=NULL):link(l){memcpy(&data,&d,sizeof(T));}//!構造函數
};
//!鏈式隊列類定義
template <class T> class Queue
{
public:
Queue():rear(NULL),front(NULL),count(0){}//!構造函數
~Queue();//!析構函數
void EnQueue(const T & item);//!將item加入到隊列中
T DeQueue();//!刪除并返回隊頭元素
T GetFront(){return front->data;}//!查看隊頭元素的值
void MakeEmpty();//!置空隊列
int IsEmpty() const {return front==NULL;}//!判斷隊列空否
int GetSize() const {return count;}
private:
QueueNode<T> *front ,*rear;//!隊頭,隊尾指針
int count;
};
typedef struct _MSG_NODE
{
unsigned long DataLength;
char pData[BUFFER_SIZE];
}MSG_NODE,*PMSG_NODE;
/*********************************************************************************/
//!通過回調函數調用上層處理函數
typedef void __stdcall ProcessRecvClientData(char * pData,unsigned long DataLength, void *pContext);
//!內部采用標準三線程模型
DWORD _stdcall SendProc(LPVOID pParam);
DWORD _stdcall WorkProc(LPVOID pParam);
DWORD _stdcall RecvProc(LPVOID pParam);
//!網絡客戶端類
class CNetClient
{
public:
CNetClient();
virtual ~CNetClient();
public:
//!初試化
/*
*ProcessRecvClientData* pProcessRecvClientData 接收數據回調函數
*void *pProcessRecvContext 接收數據回調函數上下文
*LPCTSTR szSvrAddr 連接地址
*unsigned long iSvrPort=SERVERPORT 連接端口
*/
bool Init(ProcessRecvClientData* pProcessRecvClientData,
void *pProcessRecvContext,
LPCTSTR szSvrAddr,
unsigned long iSvrPort=SERVERPORT,
BOOL bEnData = TRUE);
//!清除跟釋放資源
void UnInit(BOOL bWait = FALSE);
//!發送數據
bool SendMsg(char * pData,unsigned long DataLength);
//!返回本地地址
LPCTSTR GetLocalIP(){return IsStart ? HostIpAddr:NULL;}
bool IsStarted(){return IsStart;}
protected:
int InitNetWork(LPCTSTR szSvrAddr,
unsigned int SvrPort=SERVERPORT,
LPCTSTR HostIpAddr=NULL);
void WriteLogString(LPCTSTR strLog);
CClientSocket m_sClient;
ProcessRecvClientData* m_pProcessRecvClientData;
void* m_pProcessRecvContext;
Queue <MSG_NODE> SendMsgQueue;
CRITICAL_SECTION SendMsgQueSection;
HANDLE hSendEvent;
Queue <MSG_NODE> RecvMsgQueue;
CRITICAL_SECTION RecvMsgQueSection;
//!開始工作事件
HANDLE hWorkEvent;
//!退出事件
HANDLE hExitEvent;
//!是否用戶進行了反初始化操作,如果是:接收線程將不再調用回調函數
bool bOprUnInit;
//!是否已經被驅動
bool IsStart;
TCHAR HostIpAddr[16];
BOOL m_bEnData;
//!線程資源
HANDLE RecvHan;
HANDLE WorkHan;
HANDLE ThreHan;
static DWORD WINAPI SendProc(LPVOID pParam);
static DWORD WINAPI WorkProc(LPVOID pParam);
static DWORD WINAPI RecvProc(LPVOID pParam);
void OnSendProc();
void OnWorkProc();
void OnRecvProc();
};
#endif //! !defined(AFX_NETCLIENT_H__CF62B9AC_911A_4CE6_81B2_55CB2588A42E__INCLUDED_)
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////CNetClient.cpp//////////////////////////
// NetClient.cpp: implementation of the CNetClient class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <atlbase.h>
#include "NetClient.h"
#include "EnDeData.h"
#include <fstream>
using namespace std;
#define W2A
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNetClient::CNetClient()
{
IsStart=false;
bOprUnInit=false;
m_pProcessRecvClientData=NULL;
m_pProcessRecvContext = NULL;
WorkHan = NULL;
RecvHan = NULL;
ThreHan = NULL;
hSendEvent=CreateEvent(NULL,false,false,NULL);
hWorkEvent=CreateEvent(NULL,false,false,NULL);
hExitEvent=CreateEvent(NULL,false,false,NULL);
}
CNetClient::~CNetClient()
{
CloseHandle(hSendEvent);
CloseHandle(hWorkEvent);
CloseHandle(hExitEvent);
}
DWORD CNetClient::SendProc(LPVOID pParam)
{
reinterpret_cast<CNetClient*>(pParam)->OnSendProc();
return 0;
}
void CNetClient::OnSendProc()
{
CNetClient * pNetClient=(CNetClient*) this;
HANDLE event[2];
event[0]=pNetClient->hSendEvent;
event[1]=pNetClient->hExitEvent;
while(true)
{
Sleep(10);
::EnterCriticalSection(&pNetClient->SendMsgQueSection);
//隊列為空,等待發送事件觸發
if(pNetClient->SendMsgQueue.IsEmpty())
{
::LeaveCriticalSection(&pNetClient->SendMsgQueSection);
//為空,或者發送完畢
ResetEvent(pNetClient->hSendEvent);
//TRACE("\nTheSendProc Is Waiting....");
DWORD Index=::WaitForMultipleObjects(2,event,false, 50);
if((Index-WAIT_OBJECT_0) == WAIT_TIMEOUT)
{
if(pNetClient->bOprUnInit)
{
return ;//應用程序請求退出
}
}
else if((Index-WAIT_OBJECT_0)==1)
{
return ;
}
}
else
{
//取下一個結點,并發送
MSG_NODE p=pNetClient->SendMsgQueue.DeQueue();
//釋放隊列
::LeaveCriticalSection(&pNetClient->SendMsgQueSection);
DWORD retlen;
bool bRet=pNetClient->m_sClient.SendMsg(p.pData,p.DataLength,&retlen,WSA_INFINITE);
if(bRet==false || retlen!=p.DataLength)
{
if(GetLastError()!=CLIENT_FUNERROR)
pNetClient->m_pProcessRecvClientData(NULL,0, pNetClient->m_pProcessRecvContext);
//pNetClient->UnInit();
}
}
}
return ;
}
DWORD CNetClient::WorkProc(LPVOID pParam)
{
reinterpret_cast<CNetClient*>(pParam)->OnWorkProc();
return 0;
}
void CNetClient::OnWorkProc()
{
CNetClient* pNetClient=(CNetClient*)this;
HANDLE event[2];
event[0]=pNetClient->hWorkEvent;
event[1]=pNetClient->hExitEvent;
while(true)
{
//Sleep(1);
::EnterCriticalSection(&pNetClient->RecvMsgQueSection);
//隊列為空,等待發送事件觸發
if(pNetClient->RecvMsgQueue.IsEmpty())
{
::LeaveCriticalSection(&pNetClient->RecvMsgQueSection);
//為空,或者發送完畢
ResetEvent(pNetClient->hWorkEvent);
//TRACE("\nTheWorkProc Is Waiting....");
DWORD Index=::WaitForMultipleObjects(2,event,false, 100);
if((Index-WAIT_OBJECT_0) == WAIT_TIMEOUT)
{
if(pNetClient->bOprUnInit)
{
return ;//應用程序請求退出
}
}
else if((Index-WAIT_OBJECT_0)==1)
{
return ;
}
}
else
{
//取下一個結點,并發送
MSG_NODE p=pNetClient->RecvMsgQueue.DeQueue();
//釋放隊列
::LeaveCriticalSection(&pNetClient->RecvMsgQueSection);
//調用回調函數,處理數據
if(m_bEnData)
{
char outData[4096];
long outLen = 4096;
DeData(p.pData, p.DataLength, outData, outLen);
pNetClient->m_pProcessRecvClientData(outData,outLen, pNetClient->m_pProcessRecvContext);
}
else
{
pNetClient->m_pProcessRecvClientData(p.pData,p.DataLength, pNetClient->m_pProcessRecvContext);
}
}
}
return ;
}
DWORD CNetClient::RecvProc(LPVOID pParam)
{
try
{
reinterpret_cast<CNetClient*>(pParam)->OnRecvProc();
}
catch (...) {
}
return 0;
}
void CNetClient::OnRecvProc()
{
char RecvBuf[BUFFER_SIZE];
DWORD retlen;
while (true)
{
//Sleep(1);
//TRACE("\nTheRecvThread Is Waiting...");
if(!m_sClient.RecvMsg(RecvBuf,BUFFER_SIZE,&retlen,WSA_INFINITE) && GetLastError()!=CLIENT_FUNERROR)
{
if(bOprUnInit)
{
return ;//應用程序請求退出
}
//連接已經被斷開,通知上層(通過調用回調函數)
m_pProcessRecvClientData(NULL,0, m_pProcessRecvContext);
//pNetClient->UnInit();
return ;
}
else
{
if(bOprUnInit)
{
return ;//應用程序請求退出
}
//沒收到字節?還是出錯
if(retlen==0 || retlen > BUFFER_SIZE)
{
m_pProcessRecvClientData(NULL,0, m_pProcessRecvContext);
//pNetClient->UnInit();
return ;
}
//將接收到的數據放到接收隊列里
MSG_NODE Msg;
Msg.DataLength=retlen;
memcpy(Msg.pData,RecvBuf,retlen);
//插入消息隊列
::EnterCriticalSection(&RecvMsgQueSection);
if(RecvMsgQueue.IsEmpty())
{
RecvMsgQueue.EnQueue(Msg);
::LeaveCriticalSection(&RecvMsgQueSection);
//如果消息隊列為空,告訴工作線程可以進行工作了
SetEvent(hWorkEvent);
}
else
{
if(RecvMsgQueue.GetSize() > 50)
{
if(!m_bEnData)
RecvMsgQueue.MakeEmpty();
}
RecvMsgQueue.EnQueue(Msg);
::LeaveCriticalSection(&RecvMsgQueSection);
}
}
}
return ;
}
bool CNetClient::Init(ProcessRecvClientData* pProcessRecvClientData,
void *pProcessRecvContext,
LPCTSTR szSvrAddr,
unsigned long iSvrPort,
BOOL bEnData)
{
if(pProcessRecvClientData==NULL //回調函數空
|| szSvrAddr==NULL //地址空
|| IsStart)//已經啟動過了
{
return false;
}
m_bEnData = bEnData;
m_sClient.m_bEnData = bEnData;
::InitializeCriticalSection(&SendMsgQueSection);
::InitializeCriticalSection(&RecvMsgQueSection);
ResetEvent(hExitEvent);
IsStart = false;
bOprUnInit = false;
m_pProcessRecvClientData = pProcessRecvClientData;
m_pProcessRecvContext = pProcessRecvContext;
int bRet=InitNetWork(szSvrAddr,iSvrPort,HostIpAddr);
if(0==bRet)
{
IsStart = true;
return true;
}
else
{
m_sClient.UnInit();
::DeleteCriticalSection(&SendMsgQueSection);
::DeleteCriticalSection(&RecvMsgQueSection);
return false;
}
}
void CNetClient::UnInit(BOOL bWait)
{
if(!IsStart)
return;
IsStart=false;
bOprUnInit=true;
if(hExitEvent)
SetEvent(hExitEvent);
if(m_sClient.m_hExitEvent)
WSASetEvent(m_sClient.m_hExitEvent);
if(RecvHan)
{
/*
if(bWait)
{
bool bloop = true;
while(bloop)
{
if(WaitForSingleObject(RecvHan, 1500) == WAIT_TIMEOUT)
{
if(RecvHan == NULL)
bloop =false;
}
else
{
bloop =false;
}
}
}
else
{
if(WaitForSingleObject(RecvHan, bWait ? INFINITE : 1500) == WAIT_TIMEOUT)
{
TerminateThread(RecvHan, -2);
}
}*/
if(WaitForSingleObject(RecvHan,3000) == WAIT_TIMEOUT)
{
TerminateThread(RecvHan, -2);
}
CloseHandle(RecvHan);
RecvHan = NULL;
}
if(WorkHan)
{
/*
if(bWait)
{
bool bloop = true;
while(bloop)
{
if(WaitForSingleObject(WorkHan, 1500) == WAIT_TIMEOUT)
{
if(WorkHan == NULL)
bloop =false;
}
else
{
bloop =false;
}
}
}
else
{
if(WaitForSingleObject(WorkHan, bWait ? INFINITE : 1500) == WAIT_TIMEOUT)
TerminateThread(WorkHan, -2);
}*/
if(WaitForSingleObject(WorkHan,3000) == WAIT_TIMEOUT)
{
TerminateThread(WorkHan, -2);
}
CloseHandle(WorkHan);
WorkHan = NULL;
}
if(ThreHan)
{
/*
if(bWait)
{
bool bloop = true;
while(bloop)
{
if(WaitForSingleObject(ThreHan, 1500) == WAIT_TIMEOUT)
{
if(ThreHan == NULL)
bloop =false;
}
else
{
bloop =false;
}
}
}
else
{
if(WaitForSingleObject(ThreHan, bWait ? INFINITE : 1500) == WAIT_TIMEOUT)
TerminateThread(ThreHan, -2);
}*/
if(WaitForSingleObject(ThreHan,3000) == WAIT_TIMEOUT)
{
TerminateThread(ThreHan, -2);
}
CloseHandle(ThreHan);
ThreHan = NULL;
}
m_sClient.UnInit();
::DeleteCriticalSection(&SendMsgQueSection);
::DeleteCriticalSection(&RecvMsgQueSection);
SendMsgQueue.MakeEmpty();
RecvMsgQueue.MakeEmpty();
m_pProcessRecvClientData=NULL;
m_pProcessRecvContext = NULL;
}
int CNetClient::InitNetWork(LPCTSTR szSvrAddr,
unsigned int SvrPort,
LPCTSTR pHostIpAddress)
{
int Error=0;
WSADATA wsaData;
memset((void *)pHostIpAddress,0,sizeof(pHostIpAddress));
//Net Start Up
/*
char Name[100];
hostent *pHostEntry;
in_addr rAddr;
Error=WSAStartup(MAKEWORD(0x02,0x02),&wsaData);
if(Error!=0)
{
Error = WSAGetLastError();
//LogStr.Format("WSAStartUp Faild With Error: %d",Error);
//WriteLogString(LogStr);
return Error;
}
//Make Version
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup( );
//WriteLogString("The Local Net Version Is not 2");
return -1;
}*/
//Get Host Ip
/*Error = gethostname ( Name, sizeof(Name) );
if( 0 == Error )
{
pHostEntry = gethostbyname( Name );
if( pHostEntry != NULL )
{
memcpy( &rAddr, pHostEntry->h_addr_list[0], sizeof(struct in_addr) );
sprintf((char * )pHostIpAddress,"%s",inet_ntoa( rAddr ));
}
else
{
Error = WSAGetLastError();
//LogStr.Format("GetHostIp faild with Error: %d",Error);
//WriteLogString(LogStr);
}
}
else
{
Error = WSAGetLastError();
//LogStr.Format("gethostname faild with Error: %d",Error);
//WriteLogString(LogStr);
}*/
//Socket Create
if(0==Error)
{
if(!m_sClient.CreateSocket(SOCK_STREAM))
{
Error=WSAGetLastError();
//LogStr.Format("Create Client Socket Faild :%d",Error);
////WriteLogString(LogStr);
return Error;
}
}
if(0==Error)
{
//fix me
USES_CONVERSION;
if(!m_sClient.ConnectSocket((char *)W2A(szSvrAddr),SvrPort))
{
Error=WSAGetLastError();
//LogStr.Format("Create Client Socket Faild :%d",Error);
//WriteLogString(LogStr);
return -1;
}
}
//啟動工作線程,并升高工作線程的等級至最高
if(0==Error)
{
unsigned long WorkID;
if((WorkHan=CreateThread(NULL,
0,
WorkProc,
this,
0,
&WorkID))==NULL)
{
Error=GetLastError();
//LogStr.Format("Create WorkThread Faild With Error %d",Error);
//WriteLogString(LogStr);
return Error;
}
SetThreadPriority(WorkHan,THREAD_PRIORITY_HIGHEST);
}
//啟動接收線程
if(0==Error)
{
unsigned long RecvID;
if((RecvHan=CreateThread(NULL,
0,
RecvProc,
this
,
0,
&RecvID))==NULL)
{
Error=GetLastError();
//LogStr.Format("Create RecvThread Faild With Error %d",Error);
//WriteLogString(LogStr);
SetEvent(hExitEvent);//退出先前創建的線程
return Error;
}
}
//啟動發送線程
if(0==Error)
{
unsigned long ThrID;
if((ThreHan=CreateThread(NULL,
0,
SendProc,
this,
0,
&ThrID))==NULL)
{
Error=GetLastError();
//LogStr.Format("Create SEND Thred Faild With Error %d",Error);
//WriteLogString(LogStr);
SetEvent(hExitEvent);//退出先前創建的線程
return Error;
}
}
return Error;
}
bool CNetClient::SendMsg(char * pData,unsigned long DataLength)
{
//未調用初始化函數
if(!IsStart || pData==NULL || DataLength==0)return false;
//構造消息
MSG_NODE Msg;
Msg.DataLength=DataLength;
memcpy(Msg.pData,pData,DataLength);
//插入消息隊列
::EnterCriticalSection(&SendMsgQueSection);
if(SendMsgQueue.IsEmpty())
{
SendMsgQueue.EnQueue(Msg);
::LeaveCriticalSection(&SendMsgQueSection);
//如果消息隊列為空,告訴等待的發送線程可以發送了
SetEvent(hSendEvent);
}
else
{
SendMsgQueue.EnQueue(Msg);
::LeaveCriticalSection(&SendMsgQueSection);
}
return true;
}
void CNetClient::WriteLogString(LPCTSTR strLog)
{
return;
}
/********************************************************************
函數名 : Queue<T>::~Queue()
輸入參數:
輸出參數:
功能描述: 隊列析構函靈敏,清空所有隊列元素
全局變量: 無
調用模塊:
附加說明:
********************************************************************/
template <class T> Queue<T>::~Queue()
{
QueueNode<T> *p=front;
while(front!=NULL)
{
p=front;
front=front->link;
delete p;
}
}
/********************************************************************
函數名 : Queue<T>::EnQueue
輸入參數:
const T & item :要插入的結點的引用
輸出參數:
功能描述: 在隊列中插入一個結點
全局變量: 無
調用模塊:
附加說明:
********************************************************************/
template <class T> void Queue<T>::EnQueue(const T & item)
{
count ++;
if(front==NULL)front=rear=new QueueNode<T>(item,NULL);
else rear=rear->link=new QueueNode<T>(item,NULL);
}
/********************************************************************
函數名 : Queue<T>::DeQueue()
輸入參數:
T :返回被刪除結點的值
輸出參數:
功能描述: 從隊列中取出一個結點,并返回該結點的值
全局變量: 無
調用模塊:
附加說明:
********************************************************************/
template <class T> T Queue<T>::DeQueue()
{
T retvalue;
memset(&retvalue,0,sizeof(T));
if(IsEmpty())
return retvalue;
count --;
QueueNode<T> * p=front;
retvalue=p->data;
front=front->link;
delete p;
return retvalue;
}
/********************************************************************
函數名 : Queue<T>::MakeEmpty()
輸入參數:
輸出參數:
功能描述: 將隊列元素清空
全局變量: 無
調用模塊:
附加說明:
********************************************************************/
template <class T> void Queue<T>::MakeEmpty()
{
if(front==NULL)return ;
QueueNode<T> * p=front;
while(front!=NULL)
{
p=front;
front=front->link;
delete p;
}
front=rear=NULL;
count = 0;
}
/*************************************************************************/
CClientSocket::CClientSocket()
{
inAddr.sin_addr.s_addr = INADDR_NONE;
m_hExitEvent = NULL;
m_Socket = 0;
m_szDestAddr[0] = '\0';
}
CClientSocket::~CClientSocket()
{
if(m_hExitEvent != NULL)
WSACloseEvent(m_hExitEvent);
}
void CClientSocket::UnInit()
{
if(m_hExitEvent != NULL)
WSACloseEvent(m_hExitEvent);
ShutDownSocket();
CloseSocekt();
m_szDestAddr[0] = '\0';
m_Socket = 0;
m_hExitEvent = 0;
// if(m_hExitEvent != (WSAEVENT)0xcccccccc)WSACloseEvent(m_hExitEvent);
}
bool CClientSocket::CreateSocket(SOCKET *pNewSocket,int iSockType)
{
if(m_hExitEvent != NULL)
WSACloseEvent(m_hExitEvent);
m_hExitEvent=WSACreateEvent();
WSAResetEvent(m_hExitEvent);
bool bok = ((*pNewSocket=WSASocket(AF_INET,iSockType,0,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)?
false:true;
if(bok)
{
int nrcvbuf=1024*68;
int err=setsockopt(*pNewSocket, SOL_SOCKET, SO_RCVBUF,(char*)&nrcvbuf, sizeof(nrcvbuf));
err=setsockopt(*pNewSocket, SOL_SOCKET, SO_SNDBUF,(char*)&nrcvbuf, sizeof(nrcvbuf));
int TimeOut=10000; //設置發送超時6秒
if(::setsockopt(*pNewSocket,SOL_SOCKET,SO_SNDTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
return 0;
}
TimeOut=10000;//設置接收超時6秒
if(::setsockopt(*pNewSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&TimeOut,sizeof(TimeOut))==SOCKET_ERROR){
return 0;
}
}
return bok;
}
bool CClientSocket::BindSocket(SOCKET BindSocket,char *szHostAddr,unsigned short iHostPort)
{
struct sockaddr_in inAddr;
inAddr.sin_addr.S_un.S_addr=inet_addr(szHostAddr);
inAddr.sin_family=AF_INET;
inAddr.sin_port=htons(iHostPort);
return (bind(BindSocket,(PSOCKADDR)&inAddr,sizeof(inAddr)))
==SOCKET_ERROR?false:true;
}
bool CClientSocket::ShutDownSocket(SOCKET nowSocket)
{
if(nowSocket)
return shutdown(nowSocket,SD_BOTH)?false:true;
return true;
}
bool CClientSocket::CloseSocket(SOCKET nowSocket)
{
bool bok = false;
if(nowSocket)
bok = (closesocket(nowSocket)==SOCKET_ERROR)?false:true;
m_Socket = 0;
return bok;
}
bool CClientSocket::SendData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time)
{
if((int)len <= 0 || len > 4096)
return true;
WSABUF DataBuf;
WSAEVENT hEvents[2];
WSAOVERLAPPED SendOverLapp;
DWORD flag;
char outData[4096];
long outLen = 4096;
if(m_bEnData)
{
EnData(data, len, outData, outLen);
DataBuf.buf=outData;
DataBuf.len=outLen;
}
else
{
DataBuf.buf=data;
DataBuf.len=len;
}
hEvents[0]=m_hExitEvent;
hEvents[1]=hSendEvent;
memset(&SendOverLapp,0,sizeof(WSAOVERLAPPED));
SendOverLapp.hEvent=hSendEvent;
flag=0;
/////////////////////////////////////
//Godzilar
int ret;
if((ret=WSASend(socket,&DataBuf,1,retlen,flag,&SendOverLapp,NULL))==0)
{
*retlen = len;
return true;
}
else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING))
{
DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,FALSE,time,FALSE);
WSAResetEvent(hSendEvent);
if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0)
{
if(EventCaused == WAIT_OBJECT_0)
SetLastError(CLIENT_FUNERROR);
return false;
}
flag=0;
return WSAGetOverlappedResult(socket,&SendOverLapp,retlen,false,&flag)?
true:false;
}
else
return false;
}
bool CClientSocket::RecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
WSABUF DataBuf;
WSAEVENT hEvents[2];
WSAOVERLAPPED RecvOverLapp;
DWORD flag;
hEvents[0]=m_hExitEvent;
hEvents[1]=hRecvEvent;
DataBuf.buf=data;
DataBuf.len=len;
memset(&RecvOverLapp,0,sizeof(WSAOVERLAPPED));
RecvOverLapp.hEvent=hRecvEvent;
flag=0;
/////////////////////////////////////
int ret;
if((ret=WSARecv(socket,&DataBuf,1,retlen,&flag,&RecvOverLapp,NULL))==0)
{
return true;
}
else if((ret==SOCKET_ERROR)&&(WSAGetLastError()==WSA_IO_PENDING))
{
DWORD EventCaused=WSAWaitForMultipleEvents(2,hEvents,false,time,false);
WSAResetEvent(hRecvEvent);
if(EventCaused == WSA_WAIT_FAILED || EventCaused == WAIT_OBJECT_0)
{
if(EventCaused == WAIT_OBJECT_0)
SetLastError(CLIENT_FUNERROR);
return false;
}
flag=0;
return WSAGetOverlappedResult(socket,&RecvOverLapp,retlen,false,&flag)?
true:false;
}
else
return false;
}
bool CClientSocket::SendDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hSendEvent,DWORD time)
{
DWORD left,idx,thisret;
left=len;
idx=0;
int oflag=0;
while(left>0)
{
if(!SendData(socket,&data[idx],left,&thisret,hSendEvent,time))
{
*retlen=0;
return false;
}
WSAResetEvent(hSendEvent);
left-=thisret;
idx+=thisret;
if(thisret==0)
{
oflag++;
if(oflag>5)
break;
}
}
*retlen=idx;
return (idx==len)?true:false;
}
bool CClientSocket::RecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen,WSAEVENT hRecvEvent,DWORD time)
{
DWORD left,idx,thisret;
left=len;
idx=0;
int oflag=0;
while(left>0)
{
if(!RecvData(socket,&data[idx],left,&thisret,hRecvEvent,time))
{
*retlen=0;
return false;
}
WSAResetEvent(hRecvEvent);
left-=thisret;
idx+=thisret;
if(thisret==0)
{
oflag++;
if(oflag>5)
break;
}
}
*retlen=idx;
return (idx==len)?true:false;
}
bool CClientSocket::SendMsg(char * data,DWORD len,DWORD *retlen,DWORD time)
{
WSAEVENT hEvent=WSACreateEvent();
bool bSend=SendDataS(m_Socket,data,len,retlen,hEvent,time);
WSACloseEvent(hEvent);
return bSend;
}
bool CClientSocket::RecvMsg(char * data,DWORD len,DWORD *retlen,DWORD time)
{
WSAEVENT hEvent=WSACreateEvent();
bool Recv=RecvData(m_Socket,data,len,retlen,hEvent,time);
WSACloseEvent(hEvent);
return Recv;
}
bool CClientSocket::ConnectSocket(char * szDestAddr,unsigned short iDestPort)
{
inAddr.sin_family=AF_INET;
inAddr.sin_port=htons(iDestPort);
inAddr.sin_addr.S_un.S_addr=inet_addr(szDestAddr);
if (inAddr.sin_addr.s_addr == INADDR_NONE)
{
LPHOSTENT lphost;
lphost = gethostbyname(szDestAddr);
if (lphost != NULL)
inAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
else
{
WSASetLastError(WSAEINVAL);
return FALSE;
}
}
strcpy(m_szDestAddr, szDestAddr);
//設置非阻塞方式連接
unsigned long ul = 1;
int ret = ioctlsocket(m_Socket, FIONBIO, (unsigned long*)&ul);
if(ret==SOCKET_ERROR) return 0;
bool bOK = (connect(m_Socket,(PSOCKADDR)&inAddr,sizeof(inAddr)))
==SOCKET_ERROR ? false:true;
if(bOK)
{
unsigned long ul1= 0 ;
ret = ioctlsocket(m_Socket, FIONBIO, (unsigned long*)&ul1);
return bOK;
}
//select 模型,即設置超時
struct timeval timeout ;
fd_set r;
FD_ZERO(&r);
FD_SET(m_Socket, &r);
timeout.tv_sec = 4; //連接超時15秒
timeout.tv_usec =50000;
ret = select(0, 0, &r, 0, &timeout);
if ( ret <= 0 )
{
bOK = false;
}
else
bOK = true;
//一般非鎖定模式套接比較難控制,可以根據實際情況考慮 再設回阻塞模式
unsigned long ul1= 0 ;
ret = ioctlsocket(m_Socket, FIONBIO, (unsigned long*)&ul1);
if(ret==SOCKET_ERROR){
bOK = false;
}
return bOK;
}
////////////////////////////////////////////////////////////////////////////////////