윈도우즈 인터넷판 장기의 실현

15087 단어 windows인터넷socket

네트워크 판 장기를 구축하려면 먼저 서버와 클라이언트, 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]
실행할 때 전역 변수charpacket[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));
            }


        }
    }

좋은 웹페이지 즐겨찾기