简单五子棋服务器
来源:互联网 发布:奥数 高斯算法 教师版 编辑:程序博客网 时间:2024/05/21 11:37
介绍
五子棋服务器主要完成两个功能:
- 保存玩家请求战斗的信息,并为玩家匹配;
- 匹配好了后直接为两玩家转发坐标数据即可。
五子棋网络对战功能:
- 指定对手名称;
- 由服务器随选择对手;
两种数据结构
连接请求数据包
// 游戏类型:随机玩家还是指定玩家名字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;
- 保存的玩家信息数据结构为
// 保存玩家信息与套接字struct PlayerInfo{ CertifyData info; SOCKET sock;};
- 线程
DWORD WINAPI ProgressMap(LPVOID lpParm);
专门处理指定对手的玩家- 线程
DWORD WINAPI ProgressList(LPVOID lpParm);
专门处理随机对战的玩家- 线程
DWORD WINAPI GameRunThread(LPVOID lpParm);
专门负责为这种对战的玩家转发消息,每一对玩家开辟一个线程(效率低,但简单实用);传递的参数的数据结构保持了两位玩家的信息和SOCKET号
// 传递给玩家开始游戏后的线程数据结构struct GameRunParm{ PlayerInfo PlayerA; PlayerInfo PlayerB;};
临界区
需要创建两个临界区,为对连个玩家队列的互斥访问
// 访问NameGame的临街区CRITICAL_SECTION cri_namedgame;// 访问RandomGame的临界区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); // 创建对map与list玩家列表处理的线程 MapProThread = CreateThread(NULL,0,ProgressMap,NULL,0,NULL); ListProThread = CreateThread(NULL,0,ProgressList,NULL,0,NULL); // 接收玩家连接 while(1) { cout<<"监听中..."<<endl; SOCKADDR_IN cliAddr; int len = sizeof(SOCKADDR_IN); ZeroMemory(&cliAddr,len); CertifyData revData; memset(&revData,'\0',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 { // 每隔200ms处理一次 Sleep(200); EnterCriticalSection(&cri_namedgame); // 遍历map,查找指定对手 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,0,GameRunThread,&runparm,0,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,0,GameRunThread,&runparm,0,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,'\0',CrtDataSize);// 玩家ArecvData = plyInfo->PlayerA;recvData.info.ISFIRST = true;int re = send(SockA,(char*)&recvData,CrtDataSize,0);cout<<"server told to "<<recvData.info.myname<<" game begin,and you play first hand!"<<endl;// 玩家BrecvData = plyInfo->PlayerB;recvData.info.ISFIRST = false;re = send(SockB,(char*)&recvData,CrtDataSize,0);cout<<"server told to "<<recvData.info.myname<<" game begin,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,(char*)&point,PSize,0); cout<<"player "<<plyInfo->PlayerA.info.myname<<" send to player " <<plyInfo->PlayerB.info.myname<<" position:( "<<point.x <<" , "<<point.y<<" )"<<endl; re = recv(SockB,(char*)&point,PSize,0); if (re == SOCKET_ERROR) { cout<<"game over"<<endl; break; } send(SockA,(char*)&point,PSize,0); cout<<"player "<<plyInfo->PlayerB.info.myname<<" send to player " <<plyInfo->PlayerA.info.myname<<" position:( "<<point.x <<" , "<<point.y<<" )"<<endl;}// 关闭资源,线程负责关闭自己的接收socketre = shutdown(SockA,SD_SEND);re = shutdown(SockB,SD_SEND);Point data;while(send(SockA,(char*)&data,PSize,0) > 0);while(send(SockB,(char*)&data,PSize,0) > 0);closesocket(SockA);closesocket(SockB);cout<<"connection "<<plyInfo->PlayerA.info.myname<<" exit."<<endl;cout<<"connection "<<plyInfo->PlayerB.info.myname<<" exit."<<endl;return 0;}
0 0
- 简单五子棋服务器
- 简单五子棋
- 简单五子棋
- Excel简单五子棋
- 简单五子棋java源码
- 如何实现简单五子棋?
- 简单的小型五子棋
- 简单五子棋算法
- 人机简单五子棋!
- java简单五子棋源代码
- java实现简单五子棋
- 简单程序设计-五子棋
- 简单五子棋AI
- 五子棋的简单AI
- 五子棋的简单实现
- 简单的控制台五子棋游戏
- 简单五子棋----C语言实现
- 简单AI的五子棋程序
- 用链表创建栈 以及用数组创建栈的区别
- Linked List Cycle
- java:ArrayList集合与HashSet集合元素重复性探讨
- 性能测试的一些参考blog
- C++析构函数,This指针,函数链
- 简单五子棋服务器
- 各种极致的树莓派玩法
- CSS清除浮动大全共8种方法
- lucene4之后的近实时搜索实现
- nginx安装
- QGraphicsView 重写drawBackGround刷新问题
- C语言声明一览
- Linux下C编程知识整理
- 第12章:继承