這是一個小型多個對戰的遊戲服務器端代碼,經過修改。
文件一: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(<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; // 等待接收數據的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庫。