游戏客户器端通信框架(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 "DSGameClient.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;
	
	srand(timeGetTime() );
	int type = rand()%2 ;
	this->ds_NetType = (NETOBJECT_TYPE )type ;
	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,"网络用户");
	 srand(timeGetTime() );
	int type = rand()%2 ;
	this->ds_NetType = (NETOBJECT_TYPE )type ;
	this->ds_Score = 0 ;
	this->ds_Health = 100 ;

	 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 ;
} 


文件五:DSGameClient.h

//-----------------------------------------------------------------------------
//  DSGameClient.h
//  用于游戏中的网络通讯架构
// 
//------------------------------------------------------------------------------
#ifndef _DSGAMECLIENT_
#define _DSGAMECLIENT_
#include "DSObject.h"

class DSGameClient
{

 public:
	 DSGameClient( char *ds_DestIP );
	 ~DSGameClient();

 public:
	 void DS_ClientProcess();//启动客户处理
	 static DWORD WINAPI DS_Send( LPVOID lpParam ) ;//发送线程
	 static DWORD WINAPI DS_Receive(LPVOID lpParam) ;//接收线程
	 int DS_SendMsg(char *buf);//向服务器发送信息
	 void DS_CleanUp();//资源的回收
     
	

 public:
	 SOCKET ds_ClientSocket ;
	 struct sockaddr_in ds_ServerAddr ;

	 DWORD ds_SendThreadID ;//发送线程的ID
	 DWORD ds_RecvThreadID ;//接收线程的ID

	 char  ds_RecvBuf[1024];//接收缓冲区
	 char  ds_SendBuf[1024];//发送缓冲区

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 );
	void DS_SendCode(char sendbuf[]);

public:
	DSObject *ds_Head ;//包留头
	int ds_EnemyNum ;
	int ds_ObjectNum ;
	int ds_RedNum ;
	int ds_BlueNum ;

	
};

#endif


文件六:DSGameClient.cpp

//-----------------------------------------------------------------------------
//  DSGameServer.cpp
//  用于游戏中的网络通讯架构
// 用于客户机的架构 
//
//
//------------------------------------------------------------------------------

#include "stdafx.h"

DSGameClient *ds_GameDebugClient;//用于全局共享数据
//-----------------------------------------------------------------------------
//函数名:
//描述:用于系统的初始化
//   主要是Win32通讯的初始化
//
//-----------------------------------------------------------------------------

DSGameClient::DSGameClient( char *ds_DestIP )
{
	WSADATA ds_Data;
	
	if(WSAStartup(MAKEWORD(2,2),&ds_Data)!=0)
	{
		printf("无法加载套接字协议栈\n");
		return ;
	}

	ds_ServerAddr.sin_family = AF_INET ;
	ds_ServerAddr.sin_port = htons(5000) ;

	ds_ServerAddr.sin_addr.s_addr = inet_addr( ds_DestIP ) ;
	ds_ClientSocket = socket(AF_INET,SOCK_STREAM,0) ;
	
	if(ds_ClientSocket==INVALID_SOCKET)
	{
		printf("套接字初始化出现错误;错误号:%d\n",WSAGetLastError());
	//	return ;
	}
	if( connect(ds_ClientSocket,(struct sockaddr *)&ds_ServerAddr,sizeof( ds_ServerAddr ) )==INVALID_SOCKET)
	{
     
		printf("连接服务器出现错误;错误号:%d\n",WSAGetLastError());
		return ;
	}

	printf("连接到游戏服务器%s成功\n",ds_DestIP);
    
	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_GameDebugClient = this ;

	if(ds_GameDebugClient == NULL )
	{
		printf("ds_GameDebugClient 创建失败\n");
		return ;
	}


} 
//-------------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------------
void DSGameClient::DS_SendCode(char sendbuf[])
{
	DSObject *p = ds_Head->ds_Next ;
    if( p== NULL )
	{
		sprintf(sendbuf,"no information");
		return ;
	}
	int ID = p->ds_ID ;
	srand( timeGetTime() );

	if(rand()%3 == 1)
	{
		sprintf(sendbuf,"#CD i%d*s0*",p->ds_ID);
	    return ;
	}
    p->ds_CurrentPos.x = rand()%29+2.0f ;
	 p->ds_CurrentPos.y = rand()%5+2.0f ;
	  p->ds_CurrentPos.z = rand()%29+2.0f ;

    sprintf(sendbuf,"#CU i%d*x%f*y%f*z%f*t%d*s%d*h%d*",
		p->ds_ID,p->ds_CurrentPos.x,p->ds_CurrentPos.y,p->ds_CurrentPos.z,
		p->ds_NetType,p->ds_Health ) ;
}
//-----------------------------------------------------------------------------
//函数名:启动发送线程
//描述:用于数据的发送
//
//-----------------------------------------------------------------------------
DWORD WINAPI DSGameClient::DS_Send( LPVOID lpParam )
{
/*{"你好吗"},
        {"跟我来"},
		{"我正在这处地区"},
		{"请求支援"},
		{"我正在攻击"},
		{"前面有敌人"},
		{"大家快跑"},
		{"你们要顶住"},
	*/

	char chatinfo[8][100]=
	{
		{"#CU i0*t0*x-2.0f*y4.0f*z-4.0f*uliubing*h100*s0*"},
		{"#CU i0*t0*x-2.0f*y5.0f*z24.0f*uliubing*h100*s0*"},
		{"#CU i0*t0*x12.0f*y4.0f*z8.0f*uliubing*h100*s0*"},
		{"#CU i0*t0*x2.0f*y3.0f*z9.0f*uliubing*h100*s0*"},
		{"#CU i0*t0*x2.0f*y5.0f*z7.0f*uliubing*h100*s0*"},
		{"#CU i0*t0*x-2.0f*y3.0f*z8.0f*uliubing*h100*s0*"},
		{"#HC i0*c2*I4*"},
		{"#NC i0*t0*x2.0f*y4.0f*z4.0f*uliubing*"},
		
	};
	
	DSGameClient *ds_Client = (DSGameClient *)lpParam ;

	while(true)
	{
		//模拟测试的流量格式
    	if( ds_Client->ds_ClientSocket != NULL )
		{
	      Sleep(10000);
		  //三种不同的发送格式
	      // int temp = rand()%9 ;
		   //int iSend = send(ds_Client->ds_ClientSocket,chatinfo[temp],strlen(chatinfo[temp]),0);
          
		  /*char ds_Send[200];
		  printf("请输入要发送的信息:");
		  cin>>ds_Send;
		  int iSend = send( ds_Client->ds_ClientSocket,ds_Send,strlen(ds_Send),0 );
		
		  printf("发送信息为:%s\n",ds_Send);
          */
		  int temp = rand()%8;
		  char sendbuf[1024];
		  strcpy(ds_Client->ds_SendBuf,chatinfo[temp]);
		  strcpy(sendbuf,ds_Client->ds_SendBuf);
		  ds_GameDebugClient->DS_SendCode(sendbuf);
		  int iSend = send( ds_Client->ds_ClientSocket,sendbuf,strlen(sendbuf),0 );
		  printf("要发送的信息是:%s\n",sendbuf);

		  if(iSend <= 0)
		  {
			 if( ds_Client->ds_ClientSocket != NULL )
			   closesocket( ds_Client->ds_ClientSocket );
			 ds_Client->ds_ClientSocket = NULL ;
			 printf("发送线程关闭\n");
			 printf("发送[%d]\n接收[%d]\n",ds_Client->ds_SendThreadID,ds_Client->ds_RecvThreadID);
			 ExitThread(ds_Client->ds_SendThreadID);
			 ExitThread(ds_Client->ds_RecvThreadID);
			 printf("发送线程关闭\n");
			 return 0;
		  }
		}
	}
	return 0;
}

//-----------------------------------------------------------------------------
//函数名:启动接收线程
//描述:用于数据的接收
//
//-----------------------------------------------------------------------------
DWORD WINAPI DSGameClient::DS_Receive( LPVOID lpParam )
{
	DSGameClient *ds_Client = (DSGameClient *)lpParam ;

	while(true)
	 {
		 fd_set ds_Read;
	     int ret ;
	     FD_ZERO(&ds_Read);
	     FD_SET(ds_Client->ds_ClientSocket,&ds_Read);

	     ret = select(0,&ds_Read,NULL,NULL,NULL) ;
	  

	   if( FD_ISSET( ds_Client->ds_ClientSocket,&ds_Read ) && ds_Client->ds_ClientSocket != NULL )	
		{

		   //通过缓冲区交互
		 char recvbuf[1024];
		 ZeroMemory(recvbuf,1024);
         int iLen=recv( ds_Client->ds_ClientSocket,recvbuf,1024,0 );
		  recvbuf[iLen]='\0';
		 ZeroMemory(ds_Client->ds_RecvBuf,1024);
		   strcpy(ds_Client->ds_RecvBuf,recvbuf );
		 printf(" 接收到信息为:%s\n",ds_Client->ds_RecvBuf);

		 ds_GameDebugClient->DS_ProcessData( recvbuf );            
		 
		 fflush(0);

		 if(iLen==SOCKET_ERROR || iLen <= 0 ||iLen != (int )strlen(recvbuf))
		 {
			printf("接收出现错误号:%d\n",WSAGetLastError());
			if( ds_Client->ds_ClientSocket != NULL )
			 closesocket( ds_Client->ds_ClientSocket );
			ds_Client->ds_ClientSocket = NULL ; 
			 printf("接收线程关闭\n");
			 printf("发送[%d]\n接收[%d]\n",ds_Client->ds_SendThreadID,ds_Client->ds_RecvThreadID);
			ExitThread(ds_Client->ds_RecvThreadID);
			ExitThread(ds_Client->ds_SendThreadID );
			printf("接收线程关闭\n");
			return 0;
		 }
		 
		}
	 }
	return 0;
}
//----------------------------------------------------------------------------
//
//
//-----------------------------------------------------------------------------
int DSGameClient::DS_SendMsg(char *buf)
{
    int iSend = send( ds_ClientSocket,buf,strlen(buf),0 );

	if(iSend != (int)strlen(buf))
		printf("发送失败\n");
	
	ZeroMemory(buf,strlen(buf) );

	return 1 ;
} 
//-----------------------------------------------------------------------------
//函数名:
//描述:用于调度
//
//-----------------------------------------------------------------------------
void DSGameClient::DS_ClientProcess()
{
	HANDLE ds_Recv,ds_Send ;
	

	ds_Recv = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)DS_Receive,this,0,&ds_RecvThreadID);
	CloseHandle(ds_Recv);

	Sleep(2000);
	ds_Send = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)DS_Send,this,0,&ds_SendThreadID);
	CloseHandle(ds_Send);
} 

//-----------------------------------------------------------------------------
//函数名:
//描述:用于资源的释放
//
//-----------------------------------------------------------------------------
void DSGameClient::DS_CleanUp()
{
	closesocket( ds_ClientSocket ) ;
    WSACleanup() ;
} 

//-----------------------------------------------------------------------------
//函数名:
//描述:析构函数用于资源的释放
//
//-----------------------------------------------------------------------------
DSGameClient::~DSGameClient()
{
	DS_CleanUp() ;
} 

//---------------------------------------------------
// 将对象加入系统的链表中
//  第一:找到尾结点
//  第二:将尾结点的next域指向要加入的结点
//        将新结点的previous域指向尾结点
//  第三:若要加入的为敌人对象则敌人的数量加一 
//        总的对象数加一
//-----------------------------------------------------------------------
int DSGameClient::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_RedNum ++ ;
	if(ds_New->ds_NetType == DSBLUE )
		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 DSGameClient::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_RedNum -- ;

	        if( p->ds_NetType == DSBLUE )
		       ds_BlueNum -- ;

			ds_ObjectNum--;
		
			free(p);
            return 1 ; 
		}
    	p = p->ds_Next ;
	}

//******************************
	//若当前链表为空 或没找到
	free( p );
    return 0;
}
//--------------------------------------------------------------------
//打印当前客户信息
//------------------------------------------------------------------
void DSGameClient::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 DSGameClient::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 ;
} 
//----------------------------------------------------------------------------------------
//客户机解码分析器
//主要分析服务器的返回信息
// 首先提取头三个字符进行标头分析
//
//---------------------------------------------------------------------------------------
int DSGameClient::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 ;
	}

	//若返回码为 #IP 则服务器要求客户方传送自己的消息
	//用户名 密码(可选) 当前位置 选取的类型(红方或蓝方)
	//服务器传送时的消息格式: <#IP i2*p0(1) > 
	// i后的2为服务器分配的ID号 p的值若为0则不需要密码 为1则要传送
	//客户机回应格式为:<#OP x1.02f*y2.30f*z0.23f*t0*uliubing*?password*>
	if( strcmp(ds_Temp ,"#IP" ) == 0 )
	{
		printf("此处完成个人信息的创建与传送到服务方\n");
		DSObject *p;

		if( ( p = DS_PlayerProcess(ID,"",2) ) == NULL )
		{
			printf("在创建个人信息时出错\n");
			return -2 ;
		}
       //信息的打包与发送
       	char ds_SendToServer[200];

		if( DS_ReturnInt(ds_Msg,'p') == 1 )
          sprintf(ds_SendToServer,"#OP i%d*x%f*y%f*z%f*t%d*u%s*?%s*",
		    p->ds_ID,p->ds_CurrentPos.x,p->ds_CurrentPos.y,
		    p->ds_CurrentPos.z,p->ds_NetType,p->ds_Username,
		    "ds_Password");
		else 
          sprintf(ds_SendToServer,"#OP i%d*x%f*y%f*z%f*t%d*u%s*",
		    p->ds_ID,p->ds_CurrentPos.x,p->ds_CurrentPos.y,
		    p->ds_CurrentPos.z,p->ds_NetType,p->ds_Username);
	
		printf("%s\n",ds_SendToServer);
		DS_SendMsg(ds_SendToServer);
	}

	//表示当前有新客户机加入或为向新机器传送其他客户机信息或在新一局中传送其他主机的资料
	//其格式为:<#NC i3*x12.0f*y23.0f*z23.02f*t1*uliubing*>
	//ID号 座标 类型
	//设计上有问题 无法处理多个记录
	else if( strcmp(ds_Temp ,"#NC" ) == 0 ) 
	{
        DSObject *p;
		if( ( p = DS_PlayerProcess( ID,ds_Msg,1 ) ) == NULL )
		{
			printf("在创建新玩家时出错\n");
		    return -2 ;
		}

		p = NULL ;
		free( p );

		return 1 ;
	}

	//表示某一玩家要更新信息
	//其格式为:<#CU i3*x12.0f*y23.0f*z23.02f*h12*s0*>
	//ID号 座标 当前生命值
	//由于网络在设计过程中可能存在一些问题 可能的新用户到时在此这前没有收到故在此
	//在进行一次检测
	else if( strcmp(ds_Temp ,"#CU" ) == 0 ) 
	{
        DSObject *p;
		if( ( p = DS_PlayerProcess( ID,ds_Msg,1 ) ) == NULL )
		{
			printf("在玩家信息刷新时出错\n");
		    return -2 ;
		}

		p = NULL ;
		free( p );
		return 1 ;
	}

	//若返回码为 #FF 则服务器上客户机已达到上限要求客户方断开
	//服务器传送时的消息格式:<#FF 当前用户已满 >
	//客户方不需要回复
	//仅需断开连接

	else if( strcmp(ds_Temp ,"#FF" ) == 0 ) 
	{
		printf("当前用户已满\n");
		return 1 ;
	}

	//若返回码为 #FP 则密码错误
	//服务器传送时的消息格式:<#FP 密码错误 >
	//客户方不需要回复
	//仅需断开连接

	else if( strcmp(ds_Temp ,"#FP" ) == 0 ) 
	{
		printf("当前密码错误\n") ;
		return 1 ;
	}

	//表示某一玩家死亡
	//其格式为:<#CD i3*s0*>
	//ID号  战绩
	//将其 Active = false ;
	
	else if( strcmp(ds_Temp ,"#CD" ) == 0 ) 
	{
        DSObject *p;

		if( ( p = DS_PlayerProcess( ID,ds_Msg,1 ) ) == NULL )
		{
			printf( "在玩家信息刷新时出错\n" ) ;
		    return -2 ;
		}

	    p->ds_Active = false ;
		p->ds_Health = 0 ;
		//此处要加上当前人数的判断
		p = NULL ;
		free( p );
		return 1 ;
	}
	//显示当前被击中 <#HC i0*c0*I8*>
	//计算被击中的次数 若损失的生命值大于当前的生命值则死亡 
	else if( strcmp(ds_Temp,"#HC") == 0)
	{
	     if( ( ID = DS_ReturnInt(ds_Msg,'I') ) == -10000 )
		 {
			 printf("执行击中操作失败\n");
			 return -2 ;
		 }
		
		 DS_PlayerProcess(ID,ds_Msg,3);	
		 return 1 ;
	}

   //表示某一玩家断开连接
	//其格式为:<#DD i4 >
	//将其所有的消息删除
	
	else if( strcmp(ds_Temp ,"#DD" ) == 0 ) 
	{
		DSObject *p ;

		if( (p = DS_PlayerProcess(ID,ds_Msg) ) != NULL )
			DS_RemoveObject(p);

		//此处应发送此信息
		return 1 ;
	}

	//表示新的战局开始
	//其格式:<#NS  又开战了 >
	//可能要与新用户加入处理方式相同
	//清空资源
	
	else if( strcmp(ds_Temp,"#NS") == 0 )
	{
		printf("新的战局开始");
		return 1;
	}

	//表示某一方获胜
	//格式为:<#ST t1 >
	//输出某一方胜
	//

    else if( strcmp(ds_Temp,"#ST") == 0 )
	{
		printf("<<<<<<<<<<<<<<<<<<<<<<<<<<,,某一方获胜>>>>>>>>>>>>>>>>>>>>>...");
		return 1 ;
	}
	
	//表示当前为聊天信息
	//格式:<#CH i0*t0<1><2>*I2*m*你好 >
	//0为群发 1为向同伴发送 2为向某一人发送 i为发送方
	
    else if( strcmp(ds_Temp,"#CH" ) == 0 )
	{
		printf("聊天信息");
		return 1 ;
	}


	return 0 ;
}
//-----------------------------------------------------------------------------------
//玩家结点的创建与维护
//type = 0 ;是对有权限可以对玩家的信息进行更新 
//type = 1 ;是对有权限可以对新玩家结点的创建
//type = 2 ; 是对自身结点的创建
//------------------------------------------------------------------------------------
DSObject* DSGameClient::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()
{
	/*
	 "#IP i0*p0*"
	 "#NC i1*t1*x0*y0*z0*uliubing*"
	 "#CU i1*t1*x0*y0*z0*"
	 "#HC i1*c2*I1*"
	 "#DD i1*"
	 "#FP i0*"
	 "#FF i0*"
	 "#CD i0*s0*"
	*/

	DS_PrintCurrentTime("当前启动");
    
      DSGameClient *ds_gameclient = new DSGameClient("127.0.0.1");
	ds_gameclient->DS_ClientProcess(); 
  
	Sleep(100000);
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章