简化后的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;
}
////////////////////////////////////////////////////////////////////////////////////