介绍
五子棋服务器主要完成两个功能:
- 保存玩家请求战斗的信息,并为玩家匹配;
- 匹配好了后直接为两玩家转发坐标数据即可。
五子棋网络对战功能:
两种数据结构
连接请求数据包
enum GamePlayerType
{
Nmae_Nobody,
Name_Random,Name_Named,};
struct CertifyData
{
GamePlayerType GameType;
bool ISFIRST;
char myname[MaxNameLen];
char opponame[MaxNameLen];
};
建立连接后转发的数据包
struct PositionData
{
Point pos;
};
采用四个线程来处理
主线程专门负责监听连接,将玩家的信息大包,再根据相应的游戏类型保存到相应的队列中:
map<string,PlayerInfo> NamedGame;
list<PlayerInfo> RandomGame;
- 线程
DWORD WINAPI ProgressMap(LPVOID lpParm); 专门处理指定对手的玩家
- 线程
DWORD WINAPI ProgressList(LPVOID lpParm); 专门处理随机对战的玩家
- 线程
DWORD WINAPI GameRunThread(LPVOID lpParm); 专门负责为这种对战的玩家转发消息,每一对玩家开辟一个线程(效率低,但简单实用);传递的参数的数据结构保持了两位玩家的信息和SOCKET号
struct GameRunParm
{
PlayerInfo PlayerA;
PlayerInfo PlayerB;
};
临界区
需要创建两个临界区,为对连个玩家队列的互斥访问
CRITICAL_SECTION cri_namedgame;
CRITICAL_SECTION cri_randomgame;
初始化资源
winsock资源的初始化 WORD wVersionRequested;
WSADATA wsaData;
ZeroMemory(&wsaData,sizeof WSADATA);
wVersionRequested = MAKEWORD(2,0);
int re = WSAStartup(wVersionRequested,&wsaData);
if(re != 0)
return;
临界区的初始化
InitializeCriticalSection(&cri_namedgame);
InitializeCriticalSection(&cri_randomgame);
主循环
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
ZeroMemory(&wsaData,sizeof WSADATA);
wVersionRequested = MAKEWORD(2,0);
int re = WSAStartup(wVersionRequested,&wsaData);
if(re != 0)
return;
InitializeCriticalSection(&cri_namedgame);
InitializeCriticalSection(&cri_randomgame);
SOCKET svrScok = socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addSvr;
addSvr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addSvr.sin_family = AF_INET;
addSvr.sin_port = htons(SERVER_PORT);
bind(svrScok,(SOCKADDR*)&addSvr,sizeof(SOCKADDR));
re = listen(svrScok,MAX_CON);
assert(re != SOCKET_ERROR);
MapProThread = CreateThread(NULL,0,ProgressMap,NULL,NULL);
ListProThread = CreateThread(NULL,ProgressList,NULL);
while(1)
{
cout<<"监听中..."<<endl;
SOCKADDR_IN cliAddr;
int len = sizeof(SOCKADDR_IN);
ZeroMemory(&cliAddr,len);
CertifyData revData;
memset(&revData,' ',CrtDataSize);
SOCKET cliSock = accept(svrScok,(SOCKADDR*)&cliAddr,&len);
assert(cliSock != INVALID_SOCKET);
recv(cliSock,(char*)&revData,CrtDataSize,0);
cout<<"玩家"<<revData.myname<<"连接建立成功"<<endl;
PlayerInfo plyerInfo = {revData,cliSock};
string str = revData.myname;
switch(revData.GameType)
{
case Name_Named:
EnterCriticalSection(&cri_namedgame);
NamedGame.insert(make_pair(str,plyerInfo));
LeaveCriticalSection(&cri_namedgame);
break;
case Name_Random:
EnterCriticalSection(&cri_randomgame);
RandomGame.push_back(plyerInfo);
LeaveCriticalSection(&cri_randomgame);
break;
}
}
}
子线程
指定对手
DWORD WINAPI ProgressMap(LPVOID lpParm)
{
typedef map<string,PlayerInfo>::iterator mapItr;
do
{
Sleep(200);
EnterCriticalSection(&cri_namedgame);
for (mapItr itr = NamedGame.begin();itr != NamedGame.end();)
{
string str = itr->second.info.opponame;
mapItr OppoItr = NamedGame.find(str);
if (OppoItr != NamedGame.end())
{
GameRunParm runparm = {itr->second,OppoItr->second};
CreateThread(NULL,GameRunThread,&runparm,NULL);
NamedGame.erase(itr++);
if(itr == OppoItr) ++itr;
NamedGame.erase(OppoItr++);
if(itr == OppoItr && OppoItr != NamedGame.end()) ++ OppoItr;
}
else
++itr;
}
} while (1);
LeaveCriticalSection(&cri_namedgame);
}
随机对手
DWORD WINAPI ProgressList(LPVOID lpParm)
{
typedef list<PlayerInfo>::iterator listItr;
do
{
Sleep(200);
EnterCriticalSection(&cri_randomgame);
listItr plyA = RandomGame.end();
if (plyA != RandomGame.end())
{
listItr plyB = plyA;
++plyB;
while(plyA != RandomGame.end() && plyB != RandomGame.end())
{
GameRunParm runparm = {*plyA,*plyB};
CreateThread(NULL,NULL);
RandomGame.erase(plyA++);
RandomGame.erase(plyB++);
plyA = plyB;
if(plyB != RandomGame.end())
++plyB;
}
}
LeaveCriticalSection(&cri_randomgame);
} while (1);
}
正式游戏线程
DWORD WINAPI GameRunThread(LPVOID lpParm)
{
GameRunParm *plyInfo = (GameRunParm*)lpParm;
SOCKET SockA = plyInfo->PlayerA.sock;
SOCKET SockB = plyInfo->PlayerB.sock;
PlayerInfo recvData;
memset(&recvData,CrtDataSize);
recvData = plyInfo->PlayerA;
recvData.info.ISFIRST = true;
int re = send(SockA,(char*)&recvData,0);
cout<<"server told to "<<recvData.info.myname<<" game begin,and you play first hand!"<<endl;
recvData = plyInfo->PlayerB;
recvData.info.ISFIRST = false;
re = send(SockB,and you play second hand!"<<endl;
int PSize = sizeof(Point);
while(1)
{
Point point = {-1,-1};
re = send(SockA,(char*)&point,PSize,0);
if (re == SOCKET_ERROR)
{
cout<<"game over"<<endl;
break;
}
send(SockB,0);
cout<<"player "<<plyInfo->PlayerA.info.myname<<" send to player "
<<plyInfo->PlayerB.info.myname<<" position:( "<<point.x
<<","<<point.y<<" )"<<endl;
re = recv(SockB,0);
if (re == SOCKET_ERROR)
{
cout<<"game over"<<endl;
break;
}
send(SockA,0);
cout<<"player "<<plyInfo->PlayerB.info.myname<<" send to player "
<<plyInfo->PlayerA.info.myname<<" position:( "<<point.x
<<","<<point.y<<" )"<<endl;
}
re = shutdown(SockA,SD_SEND);
re = shutdown(SockB,SD_SEND);
Point data;
while(send(SockA,(char*)&data,0) > 0);
while(send(SockB,0) > 0);
closesocket(SockA);
closesocket(SockB);
cout<<"connection "<<plyInfo->PlayerA.info.myname<<" exit."<<endl;
cout<<"connection "<<plyInfo->PlayerB.info.myname<<" exit."<<endl;
return 0;
}
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|