欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用socks5将游戏的服务器连接通过本地SS服务器代理连接到加速服务器,实现游戏加速。

程序员文章站 2022-05-10 14:55:25
...

水平有限,简单记录下实现过程:

首先准备一个开源项目* https://sourceforge.net/p/*/code/ci/master/tree/ (c++ mfc *源码)。

*是一个本地代理服务器,*是一个Windows下C++版的*客户端. 相比其它的客户端更稳定更快速,不会出现其它版本中常现的接收数据错误。

通过*可以启动本地代理服务器。你可以让IE或其他需要软件通过SOCKS5访问的软件先连接到 *,*再将请求加密后再连接到服务器。服务器可以将请求转发到国外游戏服务器,实现网络游戏加速。

*界面:

使用socks5将游戏的服务器连接通过本地SS服务器代理连接到加速服务器,实现游戏加速。

*是开源的。本文将*的功能整合起来。实现对魔兽世界怀旧服LH网络加速的功能。

原理很简单:

1、先整合*的功能,将本地服务器启动起来。

// 加载ss服务器列表
	CSSConfigInfo *pCfg = GetConfigInfo();


	CSSNodeInfo* pNode = new CSSNodeInfo(0);
	

	pNode->id = 0;
	pNode->server = "140.0.0.00";
	pNode->server_port = 65501;
	pNode->password = "1234";	

	pNode->method = "aes-256-cfb";
	pNode->enable = true;
	pNode->Upload_traffic = 7450.00;
	pNode->Download_traffic = 21477.00;
	pNode->ConnectedTimes = 12;
	pNode->lastStatus = -1;
	pCfg->ssNodeInfo.clear();
	pCfg->ssNodeInfo.push_back(pNode);

	pCfg->localSocksUser = "local_user";
	pCfg->localSocksPass = "local_pass";
	pCfg->localPort = 1080;
	pCfg->isPrivoxyRunned = RunPrivoxy( );
	RestartLocalSocketService(FALSE);

那么本地服务器就启动好了。127.0.0.1:1080  登陆账号:local_user    登陆密码:local_pass

2、启动魔兽世界6.0。注入DLL,拦截ws2_32.dll的connect方法。

DetourRestoreAfterWith();//恢复原来的状态
	DetourTransactionBegin();//拦截开始
	DetourUpdateThread(GetCurrentThread());//刷新当前线程 
	

	
	//以下为hook connect内容
	g_trueConnect = (_gconnect)DetourFindFunction("Ws2_32.dll", "connect");
	g_trueWSAConnect = (_gWSAConnect)DetourFindFunction("Ws2_32.dll", "WSAConnect");


	DetourAttach(&(PVOID&)g_trueConnect,hook_connect);
	DetourAttach(&(PVOID&)g_trueWSAConnect,hook_WSAConnect);


	if( DetourTransactionCommit() == NO_ERROR )//拦截生效
	{
		WriteLog(_T("hook success"));
	}
	else
		WriteLog(_T("hook faild"));
int _stdcall hook_connect(SOCKET s, struct sockaddr *name, int namelen)
{
	
	CString strDbgInfo;
	strDbgInfo.Format(_T("Socket in hook connect:%d"),s);
	
	

	//修改目的IP为VIP
	SOCKADDR_IN* addr =(SOCKADDR_IN*)name;
	//如果IP是指定要修改端口的IP,就改掉端口
	char * ipaddr=NULL;
	ipaddr = inet_ntoa(addr->sin_addr);

	
	//原游戏连接信息
	TCHAR temp[255];
	memset(temp,0,255);	

	char* proxyserver = "127.0.0.1";
	int proxyport = 1081;

	char* proxyuser = "local_user";
	char* proxypwd = "local_pass";
	int iRet = ConnecToProxyServer(s,proxyserver,proxyport,proxyuser,proxypwd,3,ipaddr,ntohs(addr->sin_port));
	if (iRet>=0)
	{
		WriteLog(_T("in connecta: connect socks5 success 1!"));
	}
	else
	{
		memset(temp,0,255);
		wsprintf(temp,_T("Err connect ss5:%d"),iRet);
		WriteLog(temp);
	}
	return iRet;
}
//代理服务器登录
//char* g_proxyserver = "140.1xx.1x.1xx";
//int  g_proxyport = 65500;
//char* g_proxyuser = "";
//char* g_proxypwd = "";
//int  g_proxyid = 3;  //2 - sock4代理 3 - sock5代理
//char server_name[100]= {0};  //真正的服务器地址
//int  server_port=8000;   //真正的服务器端口
int ConnecToProxyServer(SOCKET m_hSocketpop,char* g_proxyserver,int g_proxyport,char* g_proxyuser,char* g_proxypwd,int g_proxyid,char* server_name,int server_port,int connectType)
{

	//原游戏连接信息
	
	SOCKADDR_IN ToAddr;
	
	memset(&ToAddr, 0, sizeof(ToAddr));
	ToAddr.sin_family = AF_INET; 
	ToAddr.sin_addr.s_addr = inet_addr(g_proxyserver);//这是我的SOCKS服务器
	ToAddr.sin_port = htons(g_proxyport); 
	
	int retCt = -1;
	if (connectType == 1)
		retCt = g_trueWSAConnect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr),NULL,NULL,NULL ,NULL);
	else
		retCt = g_trueConnect(m_hSocketpop,(SOCKADDR*)&ToAddr,sizeof(ToAddr));

	if( SOCKET_ERROR == retCt )
	{
		int iErr = WSAGetLastError();		
		
		if (iErr==WSAEWOULDBLOCK)
		{
			fd_set fdWrite;
			timeval tv;
			FD_ZERO(&fdWrite);//初始化fd_set
			FD_SET(m_hSocketpop,&fdWrite);
			tv.tv_sec = 30;
			tv.tv_usec = 0;
			int nRet = select(0,NULL,&fdWrite,NULL,&tv);
			if (nRet<=0)
			{
				closesocket(m_hSocketpop);
				return -111;
			}
		}
		else
		{
			closesocket(m_hSocketpop);
			return -112;
		}
	}
	char buf[100] = {0};
	if(g_proxyid == 3) //sock5 代理方式
	{
		// 让PROXY选择认证方法
		buf[0] = 0x05;
		buf[1] = 0x02; //确认2种认证方式 无需认证和需要认证
		buf[2] = 0x00; // 无需认证
		buf[3] = 0x02; // 需要认证
		WriteLog(_T("Send a request asking if authentication is required"));
		if(send(m_hSocketpop,(const far char*)buf,4,0) == SOCKET_ERROR)
		{
			closesocket(m_hSocketpop);
			return -12;
		}
		
		//查询是否有返回
		fd_set fdread;
		timeval tv;
		FD_ZERO(&fdread);//初始化fd_set
		FD_SET(m_hSocketpop,&fdread);
		tv.tv_sec = 30;
		tv.tv_usec = 0;
		int nRet;
		nRet = select(0,&fdread,NULL,NULL,&tv);
		if (nRet<=0)
		{
			return -122;
		}
		//接收返回
		if(recv(m_hSocketpop,buf,10,0) == SOCKET_ERROR)
		{
			closesocket(m_hSocketpop);
			return -13;
		}
		if(buf[1] == 0x02)
		{
			//需要认证
			WriteLog(_T("need auth"));
			char userStr[128] = {0};
			userStr[0]=0x01;
			userStr[1]=strlen(g_proxyuser);
			strcpy(userStr+2,g_proxyuser);
			userStr[2+ strlen(g_proxyuser)]= strlen(g_proxypwd);
			strcpy(userStr+3+ strlen(g_proxyuser),g_proxypwd);
			int result=send(m_hSocketpop,userStr,strlen(userStr), 0);
			if(result == SOCKET_ERROR)
			{
				closesocket(m_hSocketpop);
				return -1;
			}
			Sleep(100);
			char validateChar[2] = {1};
			result=recv(m_hSocketpop,validateChar,2, 0);
			if(result == SOCKET_ERROR)
			{
				closesocket(m_hSocketpop);
				return -1;
			}
			if(validateChar[1]!='\x00')
			{//认证失败
				closesocket(m_hSocketpop);
				return -1;
			}
		}
		// 向PROXY服务器发送CONNECT 请求,
		WriteLog(_T("Send connect request to PROXY server!"));
		memset(buf, 0, 100);
		buf[0] = 0x05;
		buf[1] = 0x01; // connection request.
		buf[2] = 0x00; // reserved!
		buf[3] = 0x01; // address type:Ip V4 ;
		*((ULONG*)(buf+4))=inet_addr(server_name);
		*((USHORT*)(buf+8))=htons(server_port);
		if(send(m_hSocketpop,(const far char*)buf,10,0) == SOCKET_ERROR)
		{
			closesocket(m_hSocketpop);
			return -14;
		}
		//Sleep(100);		
		FD_ZERO(&fdread);//初始化fd_set
		FD_SET(m_hSocketpop,&fdread);
		tv.tv_sec = 30;
		tv.tv_usec = 0;
		nRet = select(0,&fdread,NULL,NULL,&tv);
		if (nRet<=0)
		{
			return -141;
		}
		// 接收PROXY服务器返回的REPLY
		memset(buf, 1, 100);
		if(recv(m_hSocketpop,buf, 20,0) == SOCKET_ERROR)
		{
			closesocket(m_hSocketpop);
			return -15;
		}
		if(buf[1] != 0) // 只有当第二个字节为0时,才表示成功。
		{
			//   printf("Cannot connect to the remote server!\n");
			closesocket(m_hSocketpop);
			return -16;
		}
		//  theApp.m_ClientSocket.Attach(m_hSocketpop);
	}
	if(g_proxyid == 2) //sock4 代理方式
	{
		int result;
		memset(buf, 0, 100);
		buf[0] = 0x04;
		buf[1] = 0x01; // connection request.
		*((USHORT*)(buf+2))=htons(server_port);
		*((ULONG*)(buf+4))=inet_addr(server_name);
		buf[8] = 0x00;
		result = send(m_hSocketpop, (const far char*)buf, 9, 0);
		if(result == SOCKET_ERROR)
		{
			closesocket(m_hSocketpop);
			return -1;
		}
		Sleep(100);
		char EchoStr[10];
		memset(EchoStr,0,10);
		result=recv(m_hSocketpop,EchoStr,8, 0);
		if(result == SOCKET_ERROR)
		{
			closesocket(m_hSocketpop);
			return -1;
		}
		if(EchoStr[1] != 90)
		{
			closesocket(m_hSocketpop);
			return -1;
		}
		//  theApp.m_ClientSocket.Attach(m_hSocketpop);
	}
	return 0;
}

游戏会建立与本地服务器的连接,本地服务器会将游戏请求通过sock5发送到服务器上。实现游戏加速。

使用socks5将游戏的服务器连接通过本地SS服务器代理连接到加速服务器,实现游戏加速。

服务端架设参考:

用*-libev架设服务器端:

https://blog.csdn.net/wwzuizz/article/details/78194159

相关标签: 技术经验积累