游戏服务器端通信框架(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);
			else
				return -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);
			else
				return -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(&ltime);
	p=localtime(&ltime);
	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(&ltime);
	p=localtime(&ltime);
	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;	        // 等待接收数据的socket
	sockaddr_in ds_Server;			// 绑定地址

	dsClientInformation ds_AcceptSocket[MAX_NUM] ;//客户机的关联消息

//以下是对网络数据的处理
public:
	//对内核链表的操作
    int	DS_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库。

http://www.itchm.com/forum-59-1.html

猜你喜欢

转载自sessdu.iteye.com/blog/1831489