⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.h

📁 网络游戏魔域的服务端与客户端完整源代码 包括详细的说明文档与开发日志
💻 H
📖 第 1 页 / 共 2 页
字号:
// 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 + -