windows网络版象棋的实现
2016-02-27 15:07
671 查看
要构建网络版象棋,首先应该创建服务器与客户端,建立socket连接
1) 开局,你是什么颜色2)选择棋子,
3)走棋
4)悔棋(悔棋悔两步)
5)认输
网络实现:
1)建立连接
a.主机,建立监听socket
b.accept
c.关闭监听socket
a.客户端,连接服务器
2)发送报文
1)服务器给客户端发送开局报文
2)选棋 发送选棋报文
3)走棋 发送走棋报文
4)悔棋
5)认输 重新开始
报文格式定义:
第一个字节表示命令字 0表示开具,1表示选其,2表示走棋,3表示悔棋,4表示认输
开局报文 [0][0或者1] 收到0表示走黑棋,收到1表示走红旗 [0][0] [0][1]
选棋报文 [1][0~31]
走棋报文 [2][0~31][x][y] x和y已经转换好的
悔棋 [3]
认输 [4][0或者1]
运行时设计
定义一个全局变量 char packet[4]用来保存报文
定义一个定时器,每秒去收socket
[code] #ifndef _Net_H__ #define _Net_H__ #ifdef WIN32 #include <WinSock2.h> #else //linux and android #endif // WIN32 class Net { public: static SOCKET _server; static SOCKET _connet; static int _isConnected; static int _isRecvComplete; static char* _recvData; static bool Listen(short port=9999); static bool isConnected(); static bool Connect(const char*ip,short port=9999); static int Send(const char*buffer,int len); //接收数据的接口 static bool RecvStart(); static bool isRecvComplete(); static char *RecvData(int &len); static DWORD WINAPI AcceptThreadFunc(void *arg); static DWORD WINAPI RecvThreadFunc(void *arg); }; #endif
首先,服务器需要listen函数,一直监听,以得到与客户端的连接
[code] bool Net::Listen(short port) { SOCKET sock=socket(AF_INET,SOCK_STREAM,0); if (sock==INVALID_SOCKET) { return false; } struct sockaddr_in addr; addr.sin_family=AF_INET; addr.sin_port=htons(port); addr.sin_addr.S_un.S_addr=INADDR_ANY; int ret=bind(sock,(struct sockaddr*)&addr,sizeof(addr)); if (ret != 0) { closesocket(sock); return false; } listen(sock,10); //10 means listen count //create a therad to accept socket _server = sock; _isConnected = 0; HANDLE hThread = CreateThread(NULL, 0, AcceptThreadFunc, NULL, 0, NULL); CloseHandle(hThread); return true; } DWORD Net::AcceptThreadFunc(void *arg) { _connet = accept(_server, NULL, NULL); _isConnected = 1; return 0; }
客户端则需要connect函数与服务器建立连接
[code] bool Net::Connect(const char*ip,short port) { _connet=socket(AF_INET,SOCK_STREAM,0); if (_connet==INVALID_SOCKET) { return false; } struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.S_un.S_addr = inet_addr(ip); int ret = connect(_connet, (struct sockaddr*)&addr, sizeof(addr)); if (ret != 0) { closesocket(_connet); return false; } return true; }
如果建立连接成功,则可以互相传递数据了,此时服务器可以关闭连接监听
[code] void SceneGame::startServer(CCObject*) { _bredSide=true; Net::Listen(); schedule(schedule_selector(SceneGame::CheckListen)); } void SceneGame::CheckListen(float) { if (Net::isConnected()) { unschedule(schedule_selector(SceneGame::CheckListen)); //game start and do some initiate game CCLog("server start game\n"); } }
服务器与客户端互相发送数据,需要send函数
[code] int Net::Send(const char*buffer,int len) { return send(_connet,buffer,len,0); }
接收数据需要receve函数保持监听
[code] bool Net::RecvStart() { _isRecvComplete=0; HANDLE hThread=CreateThread(NULL,0,RecvThreadFunc,NULL,0,NULL); CloseHandle(hThread); return true; } bool Net::isRecvComplete() { return _isRecvComplete; } char *Net::RecvData(int &len) { len=0; _isRecvComplete=0; return _recvData; } DWORD Net::RecvThreadFunc(void *arg) { static char buf[16]; recv(_connet,buf,1,0); if (buf[0]==1) { recv(_connet,&buf[1],1,0); }else if(buf[0]==2) { for (int i=1;i<=3;i++) { recv(_connet,&buf[i],1,0); } } //stop receve _recvData=buf; _isRecvComplete=1; return 0; }
在象棋中调用发送数据,发送完毕之后轮到对方走了,此时要打开接收数据监听
[code] //send step Step* step = *_steps.rbegin(); char buf[4]; buf[0] = 2; buf[1] = step->moveid; buf[2] = step->rowTo; buf[3] = step->colTo; Net::Send(buf, 4); //receive message Net::RecvStart(); schedule(schedule_selector(SceneGame::CheckRecv));
接收到数据之后要关闭接收监听,然后开始发送数据,象棋根据传递的报文判断对方的信息,分别以1,2,3开头,表示选择,走棋,其中1与3还需要继续接收数据,2可以关闭数据接收。
[code] void SceneGame::CheckRecv(float) { if (Net::isRecvComplete()) { unschedule(schedule_selector(SceneGame::CheckRecv)); int len; char *data=Net::RecvData(len); //accord to the data protocoal do some work if (data[0]==1) { //selected _selectid=data[1]; _selectSprite->setPosition(_s[_selectid]->fromPlate()); _selectSprite->setVisible(true); //continue receive Net::RecvStart(); schedule(schedule_selector(SceneGame::CheckRecv)); } else if(data[0]==2) { //move stone Stone* s = _s[data[1]]; int row = 9 - data[2]; int col = 8 - data[3]; int killid = getStoneFromRowCol(row, col); recordStep(_selectid, killid, _s[_selectid]->_row, _s[_selectid]->_col, row, col); // 移动棋子 s->_row = row; s->_col = col; s->setPosition(s->fromPlate()); if (killid != -1) { Stone* ks = _s[killid]; ks->_dead = true; ks->setVisible(false); } _selectid = -1; _selectSprite->setVisible(false); _bRedTurn = !_bRedTurn; }else if(data[0]==3) { doRegret2(); //continue receive Net::RecvStart(); schedule(schedule_selector(SceneGame::CheckRecv)); } } }
相关文章推荐
- 网络流(最大独立点集):POJ 1466 Girls and Boys
- 003_Http之response状态码
- Z-stack 应用程序编程接口(API)-网络层
- OkHttp使用教程
- 002_Http之介绍
- VS2010创建并使用DLL http://www.cnblogs.com/laogao/archive/2012/12/07/2806528.html
- XMLHttpRequest cannot load 跨域问题解决
- 片上网络
- 片上网络
- 【转】iOS,Android网络抓包教程之tcpdump
- 太原网络营销师讲百度竞价(SEM)如何快速掌握上手公司的竞价账户?
- centos的nginx+https配置
- 神经网络分类
- Wireshark基本介绍和学习TCP三次握手
- httpclient以post方式发送body
- 如何查看自己电脑的IP和网络运营商
- [神经网络]2.1-How the backpropagation algorithm works-Warm up: a fast matrix-based approach ...(翻译)
- 自己写的一个简单的BP神经网络代码
- 安装andriod studio时出现Internal error. Please report to https://code.google.com/p/an
- okHttp的用法