遊戲客戶器端通信框架(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);
}



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