📄 socket.h
字号:
// Socket.h
// zengsong, 2001.9.25
#ifndef _SOCKET_H
#define _SOCKET_H
#include <windows.h>
#include <winsock.h>
#include <assert.h>
#include "EncryptClient.h"
////////////////////////////////////////////////////////////////////////////
//#define LOGFILE
#define ENCRYPT
////////////////////////////////////////////////////////////////////////////
//const int _MAX_MSGSIZE =1024; //??? 可能重复定义
#define ACCOUNT_KEY1 // A = 0xB2, B = 0x9B, C = 0x53, first = 0xCF, key = f2cfa8cc
#define ACCOUNT_KEY2 // A = 0xFC, B = 0xC9, C = 0xD9, first = 0xC6, key = 78c6fa82
#define LOGIN_KEY1 // A = 0x20, B = 0xFD, C = 0x07, first = 0x1F, key = a61fce5e
#define LOGIN_KEY2 // A = 0x7A, B = 0xCF, C = 0xE5, first = 0x3F, key = 443ffc04
////////////////////////////////////////////////////////////////////////////
#ifdef LOGFILE
void LogSave (const char* fmt, ...);
#endif
#define BLOCKSECONDS 30 // INIT函数阻塞时间
#define INBUFSIZE (64*1024) //? 具体尺寸根据剖面报告调整
#define OUTBUFSIZE (8*1024) //? 具体尺寸根据剖面报告调整。当不超过8K时,FLUSH只需要SEND一次
#define SOCKETLOGFILE "Socket.h"
//void SaveLog(const char * sFormat, ...);
//#define LOGCATCH SaveLog
/*
#ifdef CLIENTSOCKET32_EXPORTS
#define DLLAPI extern "C" _declspec(dllexport)
#else
#define DLLAPI extern "C" _declspec(dllimport)
#endif
#define DLLAPI
DLLAPI BOOL __stdcall ClientSocketInit (char* pszServerIP, int nServerPort);
DLLAPI BOOL __stdcall ClientSocketSendMsg (void* pBuf, int nSize);
DLLAPI BOOL __stdcall ClientSocketReceiveMsg(void* pBuf, int& nSize);
DLLAPI BOOL __stdcall ClientSocketCheck (void);
DLLAPI void __stdcall ClientSocketDestroy (void);
//*/
/*
#ifdef _DEBUG
// 调试用的宏定义
#define LogSave(x) SaveLog("*SOCKET* "x"\n")
#define LogSave(x,y) SaveLog("*SOCKET* "x"\n",(y))
#define LogSave(x,y,z) SaveLog("*SOCKET* "x"\n",(y),(z))
#define PF_INBUFCOUNT 1000 //? 调试INBUF尺寸的循环次数
#define PF_OUTBUFCOUNT 500 //? 调试OUTBUF尺寸的循环次数
#define SOCKETLOGFILE "Socket.log"
void SaveLog(const char * sFormat, ...);
#else // _DEBUG
#define LogSave(x)
#define LogSave(x,y)
#define LogSave(x,y,z)
#endif // _DEBUG
//*/
/////////////////////////////////////////////////////////////////////
template <unsigned char a1, unsigned char b1, unsigned char c1, unsigned char fst1,
unsigned char a2, unsigned char b2, unsigned char c2, unsigned char fst2>
class CGameSocket {
protected:
SOCKET m_sockClient;
BOOL m_bState;
char m_bufInput[INBUFSIZE];
int m_nInbufLen;
int m_nInbufStart; // INBUF使用循环式队列,该变量为队列起点,0 - (SIZE-1)
char m_bufOutput[OUTBUFSIZE]; //? 可优化为指针数组
int m_nOutbufLen;
#ifdef ENCRYPT
// 加密对象
typedef CEncryptClient<a1, b1, c1, fst1, a2, b2, c2, fst2> ENCRYPTCLIENT;
ENCRYPTCLIENT m_cSendEncrypt;
ENCRYPTCLIENT m_cRecvEncrypt;
#endif // ENCRYPT
#ifdef _DEBUG_X
// 调试用的变量
int pf_nInbufAverage;
int pf_nInbufMax;
int pf_nInbufCount;
int pf_nOutbufAverage;
int pf_nOutbufMax;
int pf_nOutbufCount;
#endif // _DEBUG
public:
CGameSocket(void);
// TODO: add your methods here.
BOOL Create(char* pszServerIP, int nServerPort, BOOL bKeepAlive = FALSE);
BOOL SendMsg(void* pBuf, int nSize);
BOOL ReceiveMsg(void* pBuf, int& nSize);
BOOL Flush(void);
BOOL Check(void);
void Destroy(void);
#ifdef ENCRYPT
void ChangeCode(DWORD dwData) { m_cSendEncrypt.ChangeCode(dwData); }
#endif
private:
BOOL RecvFromSock(void); // 从网络中读取尽可能多的数据
};
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG_X
// 调试用的变量
int pf_nInbufAverage;
int pf_nInbufMax;
int pf_nInbufCount;
int pf_nOutbufAverage;
int pf_nOutbufMax;
int pf_nOutbufCount;
#endif
//#define TEST //?????????????????????????????????????????????
template <unsigned char a1, unsigned char b1, unsigned char c1, unsigned char fst1,
unsigned char a2, unsigned char b2, unsigned char c2, unsigned char fst2>
CGameSocket<a1, b1, c1, fst1, a2, b2, c2, fst2>::CGameSocket()
{
// 初始化
m_bState = false;
#ifndef TEST
DeleteFile(SOCKETLOGFILE);
#endif
}
template <unsigned char a1, unsigned char b1, unsigned char c1, unsigned char fst1,
unsigned char a2, unsigned char b2, unsigned char c2, unsigned char fst2>
BOOL CGameSocket<a1, b1, c1, fst1, a2, b2, c2, fst2>::Create(char* pszServerIP, int nServerPort, BOOL bKeepAlive /*= FALSE*/)
{
try
{
if(m_bState) // 用于重新初始化
Destroy();
// 检查参数
try
{
if(pszServerIP == 0 || strlen(pszServerIP) > 15)
{
#ifdef LOGFILE
LogSave("ERROR: IP addr too long.");
#endif
exit(5);
}
}
catch(...)
{
#ifdef LOGFILE
LogSave("CATCH ERROR: Init() parameter [pszServerIP] is invalid point.");
#endif
exit(5);
}
WSADATA cData;
if(WSAStartup(0x0101, &cData) != 0)
{
#ifdef LOGFILE
LogSave("ERROR: WSAStartup() failed.");
#endif
return false;
}
if(cData.wVersion != 0x0101)
{
#ifdef LOGFILE
LogSave("ERROR: unmatched Socket version[0x%04X].", cData.wVersion);
#endif
WSACleanup();
return false;
}
// 创建主套接字
// sockaddr_in sin;
m_sockClient = socket(PF_INET, SOCK_STREAM, 0);
if(m_sockClient == INVALID_SOCKET)
{
int err = WSAGetLastError();
#ifdef LOGFILE
LogSave("ERROR %d: Init socket() failed.", err);
#endif
WSACleanup();
return FALSE;
}
// 设置SOCKET为KEEPALIVE
if(bKeepAlive)
{
int optval=1;
if(setsockopt(m_sockClient, SOL_SOCKET, SO_KEEPALIVE, (char *) &optval, sizeof(optval)))
{
int err = WSAGetLastError();
#ifdef LOGFILE
LogSave("ERROR %d: Init setsockopt() failed.\n", err);
#endif
closesocket(m_sockClient);
WSACleanup();
return FALSE;
}
}
// 设置为非阻塞方式
//*
unsigned long i = 1;
if(ioctlsocket(m_sockClient, FIONBIO, &i))
{
int err = WSAGetLastError();
#ifdef LOGFILE
LogSave("ERROR %d: Init ioctlsocket() failed.", err);
#endif
closesocket(m_sockClient);
WSACleanup();
return FALSE;
}
//*/
unsigned long serveraddr = inet_addr(pszServerIP);
if(serveraddr == INADDR_NONE) // 检查IP地址格式错误
{
#ifdef LOGFILE
LogSave("ERROR: IP地址[%s]格式错误.", pszServerIP);
#endif
closesocket(m_sockClient);
WSACleanup();
return false;
}
sockaddr_in addr_in;
memset((void *)&addr_in, sizeof(addr_in), 0);
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(nServerPort);
addr_in.sin_addr.s_addr = serveraddr;
if(connect(m_sockClient, (sockaddr *)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)
{
int err = WSAGetLastError();
if(err != WSAEWOULDBLOCK)
{
#ifdef LOGFILE
LogSave("ERROR %d: Connect() failed.", err);
#endif
closesocket(m_sockClient);
WSACleanup();
return false;
}
else // WSAWOLDBLOCK
{
timeval timeout;
timeout.tv_sec = BLOCKSECONDS;
timeout.tv_usec = 0;
fd_set writeset, exceptset;
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
FD_SET(m_sockClient, &writeset);
FD_SET(m_sockClient, &exceptset);
int ret = select(FD_SETSIZE, NULL, &writeset, &exceptset, &timeout);
if (ret == 0)
{
#ifdef LOGFILE
LogSave("ERROR : select连接超时。");
#endif
closesocket(m_sockClient);
WSACleanup();
return false;
}
else if(ret < 0)
{
int err = WSAGetLastError();
#ifdef LOGFILE
LogSave("ERROR %d: select连接错误。", err);
#endif
closesocket(m_sockClient);
WSACleanup();
return false;
}
else // ret > 0
{
if(FD_ISSET(m_sockClient, &exceptset)) // or (!FD_ISSET(m_sockClient, &writeset)
{
#ifdef LOGFILE
LogSave("ERROR : select连接例外。");
#endif
closesocket(m_sockClient);
WSACleanup();
return false;
}
}
}
}
m_nInbufLen = 0;
m_nInbufStart = 0;
m_nOutbufLen = 0;
m_bState = true;
#ifdef ENCRYPT
m_cSendEncrypt.Init();
m_cRecvEncrypt.Init();
#endif
#ifdef _DEBUG_X
pf_nInbufAverage = 0;
pf_nInbufMax = 0;
pf_nInbufCount = 0;
pf_nOutbufAverage = 0;
pf_nOutbufMax = 0;
pf_nOutbufCount = 0;
#endif
return true;
}
catch(...) {
#ifdef LOGFILE
LogSave("CATCH ERROR: Init() failed.");
#endif
exit(5);
}
}
template <unsigned char a1, unsigned char b1, unsigned char c1, unsigned char fst1,
unsigned char a2, unsigned char b2, unsigned char c2, unsigned char fst2>
BOOL CGameSocket<a1, b1, c1, fst1, a2, b2, c2, fst2>::SendMsg(void* pBuf, int nSize)
{
try
{
if(pBuf == 0 || nSize <= 0 || nSize > _MAX_MSGSIZE)
{
#ifdef LOGFILE
LogSave("ERROR: SendMsg()参数错误.");
#endif
exit(5);
}
if(!m_bState)
{
#ifdef LOGFILE
LogSave("ERROR: 连接已经断开,无法SEND.");
#endif
return false; // 状态已错
}
// 检查通讯消息包长度
try
{
int packsize = *(unsigned short *)pBuf;
if(packsize <= 0 || packsize > _MAX_MSGSIZE) //? 检测消息包尺寸错误
{
#ifdef LOGFILE
LogSave("ERROR:想发送一个消息包尺寸超长[%d]的消息!!!", packsize);
#endif
Destroy();
exit(5);
}
if(packsize != nSize)
{
#ifdef LOGFILE
LogSave("ERROR:CGameSocket::SendMsg()长度参数[%d]和消息头长度[%d]不相同!!!", nSize, packsize);
#endif
Destroy();
exit(5);
}
}
catch(...)
{
#ifdef LOGFILE
LogSave("CATCH ERROR: SendMsg() parameter pBuf is invalid point.");
#endif
exit(5);
}
// 检测BUF溢出
if(m_nOutbufLen + nSize > OUTBUFSIZE)
{
// 立即发送INBUF中的数据,以清空INBUF。
Flush();
if(m_nOutbufLen + nSize > OUTBUFSIZE)
{
#ifdef LOGFILE
LogSave("ERROR: OUTBUF溢出!!! 可能是 send() 阻塞");
#endif
Destroy();
return FALSE;
}
}
// 数据添加到BUF尾
memcpy(m_bufOutput + m_nOutbufLen, pBuf, nSize);
#ifdef ENCRYPT
// 消息加密
if(a1 || b1 || c1 || fst1 || a2 || b2 || c2 || fst2)
m_cSendEncrypt.Encrypt((unsigned char *)m_bufOutput + m_nOutbufLen, nSize);
#endif
m_nOutbufLen += nSize;
assert(m_nOutbufLen <= OUTBUFSIZE);
#ifdef _DEBUG_X
if(pf_nOutbufCount >= PF_OUTBUFCOUNT)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -