游戏服务器端通信框架(C++与Socket)
这是一个小型多个对战的游戏服务器端代码,经过修改。
文件一:stdafx.h
//-------------------------------------//stdafx.h中的函数为全局共享////版权所有 DreamShip////-------------------------------------#ifndef _STDAFX_#define _STDAFX_#include <stdio.h>#include <stdlib.h>#include <string.h>#include <iostream.h>#include <winsock2.h>#include<time.h>#include "DSGameServer.h"#include "DSObject.h"//-------------------------------// 字符解码调用函数// 在一串字符中寻找ds_Search中后的数据// 有浮点型 整形 字符型 // ////------------------------------float DS_ReturnFloat(char *ds_Dest,char ds_Search) ;int DS_ReturnInt(char *ds_Dest,char ds_Search) ;int DS_ReturnString(char *ds_Dest,char ds_Search,char *buf ) ;int DS_ReturnCharPosition( char *ds_Dest,char ds_Search );//检测当前耗时void DS_PrintTime( long time );void DS_GetCurrentTime( char timeBuf[] );void DS_PrintCurrentTime( char *ds_Msg );#endif
文件二:stdafx.cpp
//----------------------------------------------//stdafx.cpp用于全局函数的定义// ////----------------------------------------------#include "stdafx.h"//-------------------------------// 字符解码调用函数// 在一串字符中寻找ds_Search中后的数据// 有浮点型 整形 字符型 // ////------------------------------float DS_ReturnFloat(char *ds_Dest,char ds_Search){long time = timeGetTime();int i=0; while( ds_Dest[i] != '\0' ){if( ds_Dest[i] == ds_Search ){int j = 0;i++; char buf[50]; while( ds_Dest[i] != '*' ){ if( ds_Dest[i] =='\0' )return -100.0f ;buf[j]=ds_Dest[i] ;i++ ; j++ ;}buf[j]='\0'; if( buf[0] >= '0' && buf[0] <= '9' )return (float)atof(buf);elsereturn -10000.0f;}i++ ;}printf("查找不成功所需时间:%d\n",timeGetTime()-time);return -10000.0f ;}//-------------------------------// 字符解码调用函数// 在一串字符中寻找ds_Search中后的数据// 有浮点型 整形 字符型 // ////------------------------------int DS_ReturnInt(char *ds_Dest,char ds_Search){long time = timeGetTime();int i=0;while( ds_Dest[i] != '\0' ){if( ds_Dest[i] == ds_Search ){int j = 0;i++; char buf[50]; while( ds_Dest[i] != '*' ){if( ds_Dest[i] =='\0' )return -100 ;buf[j]=ds_Dest[i] ;i++ ;j++ ;}buf[j]='\0';if( buf[0] >= '0' && buf[0] <= '9' ) return atoi(buf);elsereturn -10000;}i++ ;}printf("查找不成功所需时间:%d\n",timeGetTime()-time);return -10000;}//-------------------------------// 字符解码调用函数// 在一串字符中寻找ds_Search中后的数据// 有浮点型 整形 字符型 // ////------------------------------int DS_ReturnString(char *ds_Dest,char ds_Search,char *buf ){long time = timeGetTime(); int i=0;while( ds_Dest[i] != '\0' ){if( ds_Dest[i] == ds_Search ){int j = 0;i++; while( ds_Dest[i] != '*' ){if( ds_Dest[i] =='\0' )return -1 ;buf[j]=ds_Dest[i] ;i++ ;j++ ;}buf[j]='\0';return 1;}i++ ;}printf("查找不成功所需时间:%d\n",timeGetTime()-time);return 0;}//---------------------------------------//用于获取当前字符的位置//////----------------------------------------int DS_ReturnCharPosition(char *ds_Dest,char ds_Search){ long time = timeGetTime(); int i=0;while( ds_Dest[i] != '\0' ){if( ds_Dest[i] == ds_Search ) return i ;i++ ;}printf("查找不成功所需时间:%d\n",timeGetTime()-time);return -1;}//---------------------------------------//用于测试当前耗时//////----------------------------------------void DS_PrintTime( long time ){ printf( " 程序耗时:%d \n " , timeGetTime()-time );}//-------------------------------------------------//获得当前时间//////------------------------------------------------------void DS_GetCurrentTime(char timeBuf[]){ struct tm *p;long ltime;time(<ime);p=localtime(<ime);strftime(timeBuf,25,"%a %d %b %Y %H:%M:%S",p);}//---------------------------------------------------//打印当前时间//////------------------------------------------void DS_PrintCurrentTime( char *ds_Msg ){char buf[29];struct tm *p;long ltime;//_strtime(buf);//printf("当前时间为:\t\t\t\t%s\n", buf);//_strdate(buf);//printf("当前日期为:\t\t\t\t%s\n", buf); time(<ime);p=localtime(<ime);strftime(buf,29,"%a %d %b %Y %H:%M:%S GMT",p);printf("%s时间:%s\n",ds_Msg,buf);}文件三:DSObject.h
//-------------------------//DSObject.h// 用于对系统的调度////---------------------------#ifndef _DSOBJECT_#define _DSOBJECT_//DSENEMY 指当前为敌人 DSBULLET 指当前类型为子弹//DSPLAYER 指当前类型为自已 DSHEAD 指当前类型为头结点 enum OBJECT_TYPE { DSENEMY,DSBULLET,DSPLAYER,DSHEAD,DSNULL};enum NETOBJECT_TYPE{ DSRED,DSBLUE,DSNETOTHERS,DSNETHEAD,DSNETNULL};struct D3DXVECTOR3 {float x ;float y ;float z ;};class DSObject{public :DSObject( OBJECT_TYPE ds_Type );DSObject();~DSObject(); virtual HRESULT DS_InitObject();//用于对象的初始化 virtual void DS_FrameMove( );//用于计算 virtual void DS_RenderScene();//用于渲染 virtual void DS_CleanUp();//清空处理 //用于网络对象的帧刷新 virtual HRESULT DS_NetFrameMove(); //用于该对象的显示 virtual void DS_NetRenderScene(); public:DSObject *ds_Previous; //前驱结点DSObject *ds_Next; //后继寻点OBJECT_TYPE ds_Type; //对象的类型bool ds_Active;//是否处于存活状态int ds_Health;//目前的生命值int ds_ID ;//对象的ID号NETOBJECT_TYPE ds_NetType ;//其网络类型 char ds_Username[20]; //客户机姓名float ds_Radius;//碰撞半径D3DXVECTOR3 ds_CurrentPos;//当前位置 int ds_Score ;//记录当前的战绩};#endif文件四:DSObject.cpp
//-------------------------//DSObject.cpp// 用于对系统的调度// 是DSEnemy DSPlayer DSBullet 的父类//---------------------------#include "stdafx.h"//---------------------------//函数名:DSObject()//作用: 为构造函数用于初始化参数//----------------------------DSObject::DSObject( OBJECT_TYPE ds_Type ){this->ds_Type = ds_Type; ds_Active = true;this->ds_NetType = DSNETNULL ;this->ds_ID = -1000 ;strcpy(ds_Username,"非网络用户"); ds_Previous = NULL ;ds_Next = NULL ;ds_Score = 0 ;}//---------------------------//函数名:DSObject()//作用: 为构造函数用于初始化网络参数//----------------------------DSObject::DSObject(){ ds_Active = true; strcpy(ds_Username,"网络用户"); ds_Previous = NULL ; ds_Next = NULL ; ds_Score = 0 ;}//---------------------------//函数名:~DSObject()//作用:析构函数//----------------------------DSObject::~DSObject(){DS_CleanUp();}//---------------------------//函数名:DS_InitObject()//作用://----------------------------HRESULT DSObject::DS_InitObject(){return S_OK;}//---------------------------//函数名:DS_FrameMove()//作用://----------------------------void DSObject::DS_FrameMove( ){ return ;} //---------------------------//函数名:DS_CleanUp()//作用://----------------------------void DSObject::DS_CleanUp(){return ;} //---------------------------//函数名:DS_RenderScene()//作用://----------------------------void DSObject::DS_RenderScene( ) {return ;} //---------------------------//函数名:DS_NetFrameMove()//作用://----------------------------HRESULT DSObject::DS_NetFrameMove(){return S_OK ;}//----------------------------//DS_NetRenderScene()////----------------------------void DSObject::DS_NetRenderScene( ){return ;} 文件五:DSGameServer.h
//-----------------------------------------// DSGameServer.h// 用于游戏中的网络通讯架构// //------------------------------------------#ifndef _DSGAMESERVER_#define _DSGAMESERVER_//最大上限人数#define MAX_NUM 150//开放的端口号#define DEFAULTPORT 12345#include "DSObject.h"//用于客户机信息的绑定//在此包括客户机的套接字 在运行其间服务器所分配的ID号//其链接的IP地址 服务器为其分配的发送者线程号struct dsClientInformation{SOCKET ds_Sock ;//当前的套接字sockaddr_in ds_Client ;//其客户机信息int ds_ID ;//服务器分配的ID号DWORD ds_RecvThreadID ;//服务器分配接收的线程号//DWORD ds_SendThreadID ;//服务器分配的发送线程号 bool ds_Active ;};//游戏服务器类//class DSGameServer{public:DSGameServer();~DSGameServer(); int DS_ProcessGameServer( );//用于线程处理int DS_SendMessage( int ID ,char *buf );//向某一客户机发送信息int DS_CheckSocket();//检测当前可用的ID号 void DS_CleanSocket( int ID );//清空ID号的套接字void DS_SendAll( char *buf,int ID = -1 ) ;//向所有的用户发送信息public:static DWORD WINAPI DS_ListenThread(void *data);//接收线程 SOCKET ds_ListenSocket; // 等待接收数据的socketsockaddr_in ds_Server;// 绑定地址dsClientInformation ds_AcceptSocket[MAX_NUM] ;//客户机的关联消息//以下是对网络数据的处理public://对内核链表的操作 intDS_AddObject( DSObject *ds_New );int DS_RemoveObject( DSObject *ds_New ); void DS_Print();//对网络数据的处理(可能为多流数据所以需要轮循处理)int DS_ProcessData( char *ds_NetData );//对所到的数据的识别与解析int DS_ParseMsgSTC( char *ds_Msg );//玩家结点的创建与维护DSObject* DS_PlayerProcess( int ID,char *ds_Msg,int type = 0 );int DS_CheckState(int ID);//检测当前的状态public:DSObject *ds_Head ;//包留头int ds_EnemyNum ;int ds_ObjectNum ;int ds_RedNum ;int ds_BlueNum ;int ds_RedCurrentNum ;//记录游戏中为红方的数量int ds_BlueCurrentNum ;//记录游戏中为蓝方的数量bool ds_IsPassword ;//是否有密码char ds_Password[50];//密码};#endif文件六:DSGameServer.cpp
#include "stdafx.h"DSGameServer *ds_GameDebugServer ;//-----------------------------------------//函数名://描述:用于系统的初始化// 主要是Win32通讯的初始化////-----------------------------------------DSGameServer::DSGameServer(){WSADATA wsaData;//加载当前协议if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){printf("无法加载套接字协议栈\n");return ;}//设置侦听套接字ds_ListenSocket=socket(AF_INET,SOCK_STREAM,0);if(ds_ListenSocket==INVALID_SOCKET){printf("套接字初始化出现错误;错误号:%d\n",WSAGetLastError());return ;}//设定服务器的信息ds_Server.sin_family=AF_INET;ds_Server.sin_port=htons( DEFAULTPORT );ds_Server.sin_addr.s_addr=htonl(INADDR_ANY);//对服务器的信息进行绑定if(bind(ds_ListenSocket,(LPSOCKADDR)&ds_Server,sizeof(ds_Server))==SOCKET_ERROR){printf("绑定出现问题错误号码:%d\n",WSAGetLastError());return ;}//进入侦听状态if(listen(ds_ListenSocket,5)==SOCKET_ERROR){printf("监听出现问题错误号码:%d\n",WSAGetLastError());return ;}//将所有信息进行初始化for(int i=0;i<MAX_NUM;i++)ds_AcceptSocket[i].ds_Sock = NULL; printf("网络通讯初始化成功\n");ds_GameDebugServer = this ;if( ds_GameDebugServer == NULL ){printf("当前创建Server出错\n"); return ;}ds_Head = new DSObject() ; ds_Head->ds_NetType = DSNETHEAD ; ds_Head->ds_Type = DSHEAD ;ds_Head->ds_ID = -1 ;ds_EnemyNum = 0 ;ds_ObjectNum = 0;ds_RedNum = 0 ;ds_BlueNum = 0 ;ds_IsPassword = false ;strcpy(ds_Password,"");}//-----------------------------------------//函数名:析构函数//描述:用于资源的释放////-----------------------------------------DSGameServer::~DSGameServer( ){if( ds_ListenSocket != NULL ) closesocket( ds_ListenSocket );WSACleanup();} //-----------------------------------------//函数名://描述:用于检测当前没有用的ID号////-----------------------------------------int DSGameServer::DS_CheckSocket( ){for(int i=0;i<MAX_NUM;i++){if( ds_AcceptSocket[i].ds_Sock == NULL )return i;}return -1;} //--------------------------------////描述:为每一个新加入的玩家创建一个接收线程// 同时若人数达到上限 则进入相应的处理////------------------------------------int DSGameServer::DS_ProcessGameServer(){ while(true){ //获取当前可用的套接字 int index = DS_CheckSocket(); sockaddr_in ds_Client ;//非正常的客户信息 int ds_Len = sizeof( ds_Client ); if( index != -1 ) { ds_AcceptSocket[index].ds_Sock=accept(ds_ListenSocket,(struct sockaddr*)&ds_AcceptSocket[index].ds_Client,&ds_Len);ds_AcceptSocket[index].ds_ID = index ;ds_AcceptSocket[index].ds_Active = false ;//用以标识是否为经过校验if( ds_AcceptSocket[index].ds_Sock == INVALID_SOCKET ){printf("连接出现错误代码: %d\n",WSAGetLastError());break;}printf("\n<<<<<<<<<<<<<<有新玩家到>>>>>>>>>\n新玩家的IP地址为:[%s],端口号:[%d]\n",inet_ntoa(ds_AcceptSocket[index].ds_Client.sin_addr),ntohs(ds_AcceptSocket[index].ds_Client.sin_port)); // 提示客户输入密码char ds_PassBuf[100];sprintf(ds_PassBuf,"#IP i%d*p0*",ds_AcceptSocket[index].ds_ID );DS_SendMessage(ds_AcceptSocket[index].ds_ID,ds_PassBuf); //创建接收者线程int ThreadID;// 线程id //调用createthread创建线程 ThreadID = (int)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(DSGameServer::DS_ListenThread), (void *)&ds_AcceptSocket[index], 0, &ds_AcceptSocket[index].ds_RecvThreadID); ThreadID = ThreadID ? 0 : 1;// 如果成功,则返回为0 if(ThreadID)// ThreadID如果不为0,则线程创建失败{ printf("线程创建失败\n"); ExitThread(ds_AcceptSocket[index].ds_RecvThreadID );} printf("********新玩家ID[%d]的接收线程创建成功*********\n",index ); }else { SOCKET ds_Accept=accept(ds_ListenSocket,(struct sockaddr*)&ds_Client,&ds_Len); if(ds_Accept==INVALID_SOCKET) {printf("连接出现错误代码: %d\n",WSAGetLastError());break; }printf("\n非正常请求的玩家IP地址为:[%s],端口号:[%d]\n",inet_ntoa(ds_Client.sin_addr),ntohs(ds_Client.sin_port)); send( ds_Accept,"#FF i0*m当前用户已满*",strlen("#FF m当前用户已满 "),0 );closesocket( ds_Accept );printf("<<<<<<<<<<非法连接玩家已断开>>>>>>>>>>>>>>..\n"); }}return 0;}//-----------------------------------------//函数名:为接收线程//描述:用select模式对IO进行管理// 首先判断该线程是否可读 若可读则取出其上的信息//-----------------------------------------DWORD WINAPI DSGameServer::DS_ListenThread(void *data){ dsClientInformation *ds_GameSocket = (dsClientInformation *)data ; while(true) { if( ds_GameSocket->ds_Sock == NULL ) { ds_GameDebugServer->DS_CleanSocket( ds_GameSocket->ds_ID );continue ; } //接收数据 char buf[1024] ; fd_set ds_Read;//基于select模式对IO进行管理 FD_ZERO(&ds_Read); FD_SET(ds_GameSocket->ds_Sock,&ds_Read); select(0,&ds_Read,NULL,NULL,NULL) ; if(FD_ISSET(ds_GameSocket->ds_Sock,&ds_Read) ) { int result = recv( ds_GameSocket->ds_Sock, buf,sizeof(buf),0 ) ; if ( result > 0 ) { buf[result] = 0 ; printf("\n玩家ID[%d]消息到: %s",ds_GameSocket->ds_ID,buf) ;ds_GameDebugServer->DS_SendAll(buf,ds_GameSocket->ds_ID) ;ds_GameDebugServer->DS_ProcessData( buf ); fflush(0) ; } else { ds_GameDebugServer->DS_CleanSocket( ds_GameSocket->ds_ID ); } } } return 1;} //-----------------------------------------//函数名:用于发送信息 //描述:////-----------------------------------------int DSGameServer::DS_SendMessage( int ID , char *buf ){ if( ID<0 )return 0 ; printf("向玩家ID%d 发送的信息是:%s\n",ID,buf); int iSend = send(ds_AcceptSocket[ID].ds_Sock,buf,strlen(buf),0 ) ; if( iSend == SOCKET_ERROR )//==WSAECONNABORTED || iSend == WSAECONNRESET { printf("向ID[%d]发送DS_SendMessage出现错误\n",ID) ;//DS_CleanSocket( ID );ds_AcceptSocket[ID].ds_Sock = NULL ; } return 1;} //----------------------------------------------------//全发送////----------------------------------------------------void DSGameServer::DS_SendAll(char *buf,int ID ){printf("向全体成员发送:%s\n",buf);for(int i=0 ; i<MAX_NUM ; i++ ){if( ds_AcceptSocket[i].ds_Sock != NULL && i != ID && ds_AcceptSocket[ID].ds_Active )DS_SendMessage(i,buf);}}//-----------------------------//用于对象的清空处理////------------------------------void DSGameServer::DS_CleanSocket( int ID ){if( ID < 0 )return ;char send[20];sprintf(send,"#DD i%d*",ID);DS_SendAll( send,ID ); printf("<<<<<<<<<<<<玩家[%d]退出游戏>>>>>>>>>>>\n",ID);DSObject *p = ds_Head->ds_Next ;while( p ){if( p->ds_ID == ID ){ printf("正在清空其在内核中的内容\n"); DS_RemoveObject( p ); break ;}p = p->ds_Next ;}ds_AcceptSocket[ID].ds_Active = false ;closesocket( ds_AcceptSocket[ID].ds_Sock ); ds_AcceptSocket[ID].ds_Sock = NULL ;printf("正在关闭他的接收线程为%d\n",ds_AcceptSocket[ID].ds_RecvThreadID ); ExitThread(ds_AcceptSocket[ID].ds_RecvThreadID );printf("***************************************\n");printf("<<<<<<<<<<<<<<关闭成功>>>>>>>>>>>>>>>>>>>>>>>\n");}//---------------------------------------------------// 将对象加入系统的链表中// 第一:找到尾结点// 第二:将尾结点的next域指向要加入的结点// 将新结点的previous域指向尾结点// 第三:若要加入的为敌人对象则敌人的数量加一 // 总的对象数加一//-----------------------------------int DSGameServer::DS_AddObject( DSObject *ds_New ){if( ds_New == NULL )return 0;DSObject *p;p = ds_Head; //找到尾结点while( p->ds_Next != NULL )p = p->ds_Next ;// 将尾结点的next域指向要加入的结点 // 将新结点的previous域指向尾结点p->ds_Next = ds_New ;ds_New->ds_Previous = p ; p = NULL ;free( p ); // 若要加入的为敌人对象则敌人的数量加一 // 总的对象数加一if( ds_New->ds_Type == DSENEMY ) ds_EnemyNum++;if(ds_New->ds_NetType == DSRED ){ds_RedCurrentNum ++ ;ds_RedNum ++ ;}if(ds_New->ds_NetType == DSBLUE ){ds_BlueCurrentNum++ ;ds_BlueNum ++ ;}ds_ObjectNum++;return 1;}//-----------------------------------------//第一:若当前链表为空 则转到//*************//第二:若为非空则遍历查找若找到该结点则// 1.若该结点位于链尾 则 p->ds_Previous->ds_Next = NULL// 2.若在链表头于尾之间则// p->ds_Previous->ds_Next = p->ds_Next ;// p->ds_Next->ds_Previous = p->ds_Previous ;//第三:若该结点为敌人则敌人数量减一// 总对象数减一 //-----------------------------------------int DSGameServer::DS_RemoveObject( DSObject *ds_New ){// 若对象这空则if( ds_New == NULL )return 0;DSObject *p;p = ds_Head->ds_Next ;//循环查找while( p != NULL ){//如果找到则清空该结点if( p == ds_New ){//若在链表头于尾之间if(ds_New->ds_Next != NULL ) { p->ds_Previous->ds_Next = p->ds_Next ; p->ds_Next->ds_Previous = p->ds_Previous ;}//若该结点位于链尾else p->ds_Previous->ds_Next = NULL ;//清空该结点p->ds_Previous = NULL ;p->ds_Next = NULL ; ds_New = NULL ;//若该结点为敌人对象则if(p->ds_Type == DSENEMY )ds_EnemyNum-- ; if( p->ds_NetType == DSRED ){ ds_RedCurrentNum --; ds_RedNum -- ;} if( p->ds_NetType == DSBLUE ){ ds_BlueCurrentNum -- ; ds_BlueNum -- ;}ds_ObjectNum--;free(p); return 1 ; } p = p->ds_Next ;}//******************************//若当前链表为空 或没找到free( p ); return 0;}//--------------------------------//打印当前客户信息//------------------------------void DSGameServer::DS_Print(){ DSObject *p;p = ds_Head->ds_Next ;printf("ID 类型 生命值 存活 战绩 <x y z > \n ");while( p ){ printf(" %d %d %d %d %d <%f,%f,%f>\n ",p->ds_ID,p->ds_NetType, p->ds_Health,p->ds_Active, p->ds_Score,p->ds_CurrentPos.x,p->ds_CurrentPos.y,p->ds_CurrentPos.z ); p = p->ds_Next ;}p = NULL ;free(p);printf("红方:%d 蓝方: %d 总人数: %d\n",ds_RedNum,ds_BlueNum,ds_ObjectNum);}//---------------------------------------------////内部解码器// 用于多发流量的解码////对于所要传输的数据是以#开头,若要在某一缓冲区内接收到了//多个命令则启动轮循检测以实现数据的准确接收////--------------------------------------------int DSGameServer::DS_ProcessData( char *ds_NetData ){ char ds_Dest[1024] ; strcpy( ds_Dest,ds_NetData ); printf("%s\n",ds_Dest); while(true) { int ds_Count = DS_ReturnCharPosition(ds_Dest,'#'); //查找工作结束 if( ds_Count == -1 ) return 0 ; char ds_Msg[100] ; ds_Msg[0] = '#' ; int count = ds_Count +1 ; int temp = 1 ; while( ds_Dest[count] != '#' && ds_Dest[count] != '\0' ) { ds_Msg[temp++] = ds_Dest[count++] ; } ds_Msg[temp] ='\0'; //对命令进行解码 printf("解析的信息为:%s\n",ds_Msg); if( ds_Msg[temp-1] == '*' ) DS_ParseMsgSTC(ds_Msg); ds_Dest[ds_Count] = '@'; } return 1 ;} //------------------------------------------------//检测当前状态//可能有问题要注意此处的用法//ID暂时用不到//------------------------------------------------int DSGameServer::DS_CheckState(int ID){if(ds_RedNum >0 && ds_BlueNum >0 )return 0 ; char send[20]; //如果蓝方胜 if(ds_RedNum <= 0) sprintf(send,"#ST i0*mBlue Success!*"); //如果红方胜 else if(ds_BlueNum <= 0) sprintf(send,"#ST i1*mBlue Success!*"); DS_SendAll(send); //对新一局进行初始化工作 float x = 12.0f ; float z = 12.0f ; DSObject *p ; p = ds_Head->ds_Next ; while( p ) { p->ds_Active = true ; p->ds_Health = 100 ; srand( timeGetTime() ); p->ds_CurrentPos.y =rand()%3+4.0f ; if( p->ds_NetType == DSRED ) { p->ds_CurrentPos.x = x+rand()%20 ; p->ds_CurrentPos.z = z+rand()%20 ; } else { p->ds_CurrentPos.x = -x-rand()%20 ; p->ds_CurrentPos.z = -z-rand()%20 ; } p = p->ds_Next ; } p = NULL ; free( p ) ; printf("执行完成了新一局的初始化\n"); DS_Print(); return 1 ; } //----------------------------------------------------//客户机解码分析器//主要分析服务器的返回信息// 首先提取头三个字符进行标头分析////---------------------------------------------------int DSGameServer::DS_ParseMsgSTC( char *ds_Msg ){//第一步校验 //检测数据的长度是否合适 <#DD i0*>//按照编码要求最小应为7个单位长度 if( strlen(ds_Msg) < 7 ){ printf("当前没有要处理的信息结构不对\n"); return -2 ;} long time = timeGetTime() ;//提取头三个字符并保存在 ds_Temp 变量中char ds_Temp[3];for( int i = 0 ; i<3 ; i++ )ds_Temp[i] = ds_Msg[i] ;ds_Temp[3] = '\0' ; //进入第二步校验 先检测ID号是否正确int ID ;if( (ID = DS_ReturnInt(ds_Msg,'i') ) == -10000 ){printf("当前要求处理的信息有误ID号不能为-10000\n");return -2 ;}//表示新客户机的信息//格式为:<#OP i2 x0.32f y2.5f z23.5f t0 uliubing %523667 >//用务器检测密码若正确则向其传送其他客户机的资料 //并同时向其他客户机传送新机的信息<#NC i3 x12.0f y23.0f z23.02f t1 >//若错误则断开并发送<#FP 密码错误 >if( strcmp(ds_Temp ,"#OP" ) == 0 ){printf("<<<<<<<<<<<正在进行校验工作>>>>>>>>>>>>>>>>>\n");//进行密码的校验if( ds_GameDebugServer->ds_IsPassword ){char password[50];//如果获取密码错误则置为空if( DS_ReturnString(ds_Msg,'?',password ) == 0 )strcpy(password,"");if( strcmp(ds_GameDebugServer->ds_Password,password ) != 0 ){ ds_GameDebugServer->DS_SendMessage( ID,"#FP i0*m密码错误*"); ds_GameDebugServer->DS_CleanSocket( ID ); return -2 ;}} // 如果通过验证则 // 1更新其在服务器的信息加入内核管理 //2 向其他客户机传送新机消息 //3 向其传送其他客户机消息 DSObject *p ; if ( ( p = ds_GameDebugServer->DS_PlayerProcess(ID,ds_Msg,1 ) ) == NULL ) { printf("加入该玩家ID[%d]出现失败\n",ID ); return -2 ; } DS_PrintCurrentTime("内核管理打印"); ds_GameDebugServer->DS_Print(); printf("***************************************************\n"); //向其他客户机发送新机器的信息 char ds_NewInfor[300]; sprintf(ds_NewInfor,"#NC i%d*t%d*x%f*y%f*z%f*u%s*", p->ds_ID,p->ds_NetType,p->ds_CurrentPos.x, p->ds_CurrentPos.y,p->ds_CurrentPos.z, p->ds_Username ); ds_GameDebugServer->DS_SendAll( ds_NewInfor,ID ); DS_PrintCurrentTime("向全体发送打印"); ds_GameDebugServer->DS_Print(); printf("***************************************************\n"); //向新玩家发送其他客户机的信息 p = ds_Head->ds_Next ; while( p ) { if( p->ds_ID != ID ) { char ds_NewInfor[300]; sprintf(ds_NewInfor,"#NC i%d*t%d*x%f*y%f*z%f*u%s*h%d*s%d*", p->ds_ID,p->ds_NetType,p->ds_CurrentPos.x, p->ds_CurrentPos.y,p->ds_CurrentPos.z, p->ds_Username,p->ds_Health,p->ds_Score ); ds_GameDebugServer->DS_SendMessage( ID,ds_NewInfor ); ZeroMemory(ds_NewInfor,300); } p = p->ds_Next ; } p = NULL ; free( p ); //为可用状态 ds_AcceptSocket[ID].ds_Active = true ; DS_PrintCurrentTime("向个人打印"); ds_GameDebugServer->DS_Print(); printf("***************************************************\n"); return 1 ; }//表示某一玩家要更新信息//其格式为:<#CU i3*x12.0f*y23.0f*z23.02f*h12*s0*>//ID号 坐标 当前生命值//由于网络在设计过程中可能存在一些问题 可能的新用户到时在此这前没有收到故在此//在进行一次检测else if( strcmp(ds_Temp ,"#CU" ) == 0 ) { printf("<<<<<<<<<<<<<<正在进行用户信息刷新工作>>>>>>>>>>>>>>>>>>>>\n") ;DSObject *p ; if( ( p = ds_GameDebugServer->DS_PlayerProcess(ID,ds_Msg,0) ) == NULL ){printf("更新失败\n");return -2 ;} ds_GameDebugServer->DS_SendAll( ds_Msg,ID ); return 1 ;}//表示某一玩家死亡//其格式为:<#CD i3*s0*>//ID号 战绩//将其 Active = false ;else if( strcmp(ds_Temp ,"#CD" ) == 0 ) { printf("<<<<<<<<<<<<<<<<<玩家挂了>>>>>>>>>>>>>>>>>>>>>>>>>\n"); DS_Print();printf("*****************************************************\n");DSObject *p ; if( ( p = ds_GameDebugServer->DS_PlayerProcess(ID,ds_Msg,0) ) == NULL ){printf("更新失败\n");return -2 ;}p->ds_Health = 0 ;p->ds_Active = false ;//此处加上检测当前人数 以便判定那方胜//应有一个返回类型 ds_GameDebugServer->DS_SendAll( ds_Msg,ID );//位置应放在这if (p->ds_NetType == DSRED )ds_RedNum -- ;else if(p->ds_NetType == DSBLUE )ds_BlueNum-- ; if(ds_RedNum >0 && ds_BlueNum >0 ) return 0 ; char send[60]; //如果蓝方胜 if(ds_RedNum <= 0) sprintf(send,"#ST i0*mBlue Success!*"); //如果红方胜 else if(ds_BlueNum <= 0) sprintf(send,"#ST i1*mRed Success!*"); printf("向全体成员发送:%s\n",send); for(int i=0 ; i<MAX_NUM ; i++ ) {if( ds_AcceptSocket[i].ds_Sock != NULL )DS_SendMessage(i,send); } printf("***************%s***********\n",send); //对新一局进行初始化工作 float x = 12.0f ; float z = 12.0f ; p = NULL ; p = ds_Head->ds_Next ; while( p ) { p->ds_Active = true ; p->ds_Health = 100 ; srand( timeGetTime() ); p->ds_CurrentPos.y =rand()%3+4.0f ; if( p->ds_NetType == DSRED ) { p->ds_CurrentPos.x = x+rand()%20 ; p->ds_CurrentPos.z = z+rand()%20 ; } else { p->ds_CurrentPos.x = -x-rand()%20 ; p->ds_CurrentPos.z = -z-rand()%20 ; } p = p->ds_Next ; } p = NULL ; free( p ) ; printf("执行完成了新一局的初始化\n"); DS_Print(); return 1 ;}//显示当前被击中 <#HC i0*c0*I8*>//计算被击中的次数 若损失的生命值大于当前的生命值则死亡 else if( strcmp(ds_Temp,"#HC") == 0){ printf("<<<<<<<<<<<<<<<<<<<<<<<某一玩家被击中>>>>>>>>>>>>>>>>>>>>>\n"); ds_GameDebugServer->DS_PlayerProcess(ID,ds_Msg,3); return 1 ;} //表示某一玩家断开连接//其格式为:<#DD i4 >//将其所有的消息删除else if( strcmp(ds_Temp ,"#DD" ) == 0 ) {printf("<<<<<<<<<<<<<<<<<<<<<<<<玩家ID[%d]要断开连接>>>>>>>>>>>>>>>>>>>>>>>>\n",ID);//此处应发送此信息//此处加上检测当前人数 以便判定那方胜 ds_GameDebugServer->DS_CleanSocket( ID ) ;ds_GameDebugServer->DS_SendAll( ds_Msg,ID ) ; return 1 ;} else if( strcmp(ds_Temp,"#BN") == 0 ){ //当前在新一局中有客户机信息到//将要更新的位置信息以#NS处理 DSObject *p ; p = ds_Head->ds_Next ; while( p ) { char ds_NewInfor[300]; sprintf(ds_NewInfor,"#NS i%d*t%d*x%f*y%f*z%f*h%d*s%d*u%s*", p->ds_ID,p->ds_NetType,p->ds_CurrentPos.x, p->ds_CurrentPos.y,p->ds_CurrentPos.z, p->ds_Health,p->ds_Score,p->ds_Username ); ds_GameDebugServer->DS_SendMessage( ID,ds_NewInfor ); ZeroMemory(ds_NewInfor,300); p = p->ds_Next ; } p = NULL ; free( p ); // 在向其发送可以开局了 ds_GameDebugServer->DS_SendMessage( ID,"#OK i0*" );return 1 ;}//表示当前为聊天信息//格式:<#CH i0*t0<1><2>*I2*m*你好 >//0为群发 1为向同伴发送 2为向某一人发送 i为发送方 else if( strcmp(ds_Temp,"#CH" ) == 0 ){printf("<<<<<<<<<<<<<<<<<<<<<<<<<聊天信息>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");return 1 ;}return 0 ;}//-----------------------------------------------//玩家结点的创建与维护//type = 0 ;是对有权限可以对玩家的信息进行更新 //type = 1 ;是对有权限可以对新玩家结点的创建//type = 2 ; 是对自身结点的创建//------------------------------------------------DSObject* DSGameServer::DS_PlayerProcess( int ID,char *ds_Msg,int type ){ //记数器若找到某一结点则变为1 int count = 0 ;//将第一个结点 DSObject *p = ds_Head ; while( p ) { if( p->ds_ID == ID ) { count = 1 ; break ; } p = p->ds_Next ; } //若找到该结点且可以更新 if( count == 1 && ( type == 1 || type == 0 ) ) //type !=2 && type!=3 { int ds_tempInt ;//用于保存整形数据 float ds_tempFloat ;//用于保存浮点形数据 //若战绩信息正确则更新 否则不处理 if( ( ds_tempInt = DS_ReturnInt(ds_Msg,'s') ) != -10000 ) p->ds_Score = ds_tempInt ; //若生命值信息正确则更新 否则不处理 if( ( ds_tempInt = DS_ReturnInt(ds_Msg,'h') ) != -10000 ) p->ds_Health = ds_tempInt ; //若X位置正确则更新 if( ( ds_tempFloat = DS_ReturnFloat(ds_Msg,'x') ) != -10000.0f ) p->ds_CurrentPos.x = ds_tempFloat ; //若y位置正确则更新 if( ( ds_tempFloat = DS_ReturnFloat(ds_Msg,'y') ) != -10000.0f ) p->ds_CurrentPos.y = ds_tempFloat ; //若z位置正确则更新 if( ( ds_tempFloat = DS_ReturnFloat(ds_Msg,'z') ) != -10000.0f ) p->ds_CurrentPos.z = ds_tempFloat ; return p ; } else if( count == 0 && type == 1 ) { int ds_tempInt ;//用于保存整形数据 float ds_tempFloat ;//用于保存浮点形数据 DSObject *ds_New = new DSObject( ); ds_New->ds_ID = ID ; //若战绩信息正确则更新 否则不处理 if( ( ds_tempInt = DS_ReturnInt(ds_Msg,'s') ) != -10000 ) ds_New->ds_Score = ds_tempInt ; //若生命值信息正确则更新 否则不处理 if( ( ds_tempInt = DS_ReturnInt(ds_Msg,'h') ) != -10000 ) ds_New->ds_Health = ds_tempInt ; //若生命值信息正确则更新 否则不处理 if( ( ds_tempInt = DS_ReturnInt(ds_Msg,'t') ) != -10000 ) ds_New->ds_NetType =(NETOBJECT_TYPE) ds_tempInt ; //若X位置正确则更新 if( ( ds_tempFloat = DS_ReturnFloat(ds_Msg,'x') ) != -10000.0f ) ds_New->ds_CurrentPos.x = ds_tempFloat ; //若y位置正确则更新 if( ( ds_tempFloat = DS_ReturnFloat(ds_Msg,'y') ) != -10000.0f ) ds_New->ds_CurrentPos.y = ds_tempFloat ; //若z位置正确则更新 if( ( ds_tempFloat = DS_ReturnFloat(ds_Msg,'z') ) != -10000.0f ) ds_New->ds_CurrentPos.z = ds_tempFloat ; if( DS_ReturnString(ds_Msg,'u',ds_New->ds_Username ) == 0 ) strcpy(ds_New->ds_Username,"匿名玩家"); DS_AddObject( ds_New ); // ds_New = NULL ; //free( ds_New ); return ds_New ; } //创建自身的结点 else if( count == 0 && type ==2 ) { DSObject *ds_Player = new DSObject(); ds_Player->ds_ID = ID ; ds_Player->ds_NetType = DSRED ; ds_Player->ds_Type = DSPLAYER ; DS_AddObject(ds_Player); return ds_Player ; } //用于击中处理 else if( count == 1 && type == 3 ) { int ds_tempInt ; if( ( ds_tempInt = DS_ReturnInt(ds_Msg,'c') ) != -10000 ) p->ds_Health -= ds_tempInt*25 ; p = NULL ; free( p ); return NULL ; } return NULL ;}文件七:DSMain.cpp
#include "stdafx.h"void main(){ DSGameServer *ds_GameServer = new DSGameServer();DS_PrintCurrentTime("游戏服务器启动");printf("*******************DreamShip制作*****************************************\n");printf("*******************版权所有**********************************************\n");ds_GameServer->DS_ProcessGameServer(); }将以上文件保存成源代码,再VC++6.0中进行编译,注意编译之前在Link中加上ws2_32.lib库。