zoukankan      html  css  js  c++  java
  • windows网络版象棋的实现

    要构建网络版象棋,首先应该创建服务器与客户端,建立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

        #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函数,一直监听,以得到与客户端的连接

        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函数与服务器建立连接

        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;
    
        }

    如果建立连接成功,则可以互相传递数据了,此时服务器可以关闭连接监听

        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
    ");
    
    
            }
        }

    服务器与客户端互相发送数据,需要send函数

        int Net::Send(const char*buffer,int len)
        {
            return send(_connet,buffer,len,0);
        }

    接收数据需要receve函数保持监听

        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;
        }

    在象棋中调用发送数据,发送完毕之后轮到对方走了,此时要打开接收数据监听

        //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可以关闭数据接收。

        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));
                }
    
    
            }
        }
  • 相关阅读:
    数据库新增“自动添加”类字段 auto_now_add 如何不影响之前数据
    django rest framework serializer中获取request中user方法
    django Table doesn't exist
    python 日期换算星期 蔡勒公式
    python pdfkit html转pdf响应式轮子 django例
    Python Excel 多sheet 多条数据 自定义写入
    Python 爬虫 Vimeo视频下载链接
    Python 快速排序 算法
    jvm内存模型
    JMV的学习
  • 原文地址:https://www.cnblogs.com/jjx2013/p/6223761.html
Copyright © 2011-2022 走看看