윈도우즈 인터넷판 장기의 실현
네트워크 판 장기를 구축하려면 먼저 서버와 클라이언트, 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));
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
제한된 크기의 디렉토리를 만드는 방법오늘 저는 장치에 공간이 없을 때 백업 중에 응용 프로그램이 어떻게 작동하는지 테스트(및 수정)하는 작업이 있습니다. 결과적으로 "남은 공간 없음"오류로 백업이 실패하면 새 파일이 없어야 합니다. 지금까지 문제를 재...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.