MFC设计局域网对战五子棋游戏(六)网络通信

网络通信部分放在了独立的线程中处理,因为使用的是CSocket,而且它是采用阻塞式的,所以需要自己使用多线程技术来接受数据,而不能再主线程中阻塞接收过程。

这是建立和搜索游戏的流程图:

 


建立游戏就是“摆擂”按钮:

void CWZQDlg::OnBnClickedServer()
{
	if(m_receving)
		return;
	m_uid = 1;
	AfxBeginThread(HostThread,this);
	AfxBeginThread(ReceiveThread,this);
}
UINT CWZQDlg::HostThread(LPVOID param)
{
	CWZQDlg* pwd = (CWZQDlg*)param;
	MsgPack msp;
	CString clientAddr;
	UINT clientPort;
	CSocket hostSock;//建立服务器,接收并回应UDP广播搜索的socket

	hostSock.Create(pwd->m_SearchPort,SOCK_DGRAM);

	pwd->SetWindowTextA("已建立服务器、等待用户");
	hostSock.ReceiveFrom(&msp,sizeof(MsgPack),clientAddr,clientPort);
	if(msp.type == SEARCH_HOST)
	{
		MsgPack hostMsg;
		hostMsg.type = HOST_RESPONSE;
		pwd->m_name.GetWindowTextA(hostMsg.data.SR.server,sizeof(hostMsg.data.SR.server)-1);
		hostMsg.data.SR.uesrNum = 1;
		Sleep(300);
		hostSock.SendTo(&hostMsg,sizeof(MsgPack),clientPort,clientAddr);
	}

	return 0;
}


搜索游戏是“搜索”按钮:

void CWZQDlg::OnBnClickedSearchgame()
{
	AfxBeginThread(SearchThread,this);
}

UINT CWZQDlg::SearchThread(LPVOID param)
{
	CWZQDlg* pwd = (CWZQDlg*)param;
	if(pwd->m_gameStart)
		return 0;
	MsgPack msp;
	UINT hostPort;
	BOOL broadcast=TRUE;
	msp.type = SEARCH_HOST;
	CSocket searchSock;//创建广播UDP socket用来搜索局域网上的服务器

	searchSock.Create(0,SOCK_DGRAM);
	searchSock.SetSockOpt(SO_BROADCAST,&broadcast,sizeof(BOOL));
	searchSock.SendTo(&msp,sizeof(MsgPack),pwd->m_SearchPort,"255.255.255.255");
	searchSock.ReceiveFrom(&msp,sizeof(MsgPack),pwd->hostAddrSock,hostPort);
	if(msp.type == HOST_RESPONSE)
	{
		LPSTR serverName = (CHAR*)::malloc(strlen(msp.data.SR.server)+1);

		strcpy_s(serverName,7,msp.data.SR.server);
		pwd->m_gameList.AddString(serverName);
	}
	return 0;
}


在网络通信部分,最关键的就是接收游戏数据的线程,服务器和客户端都使用这个线程:

 

UINT CWZQDlg::ReceiveThread(LPVOID param)
{
	CWZQDlg* pwd = (CWZQDlg*)param;
	if(pwd->m_gameStart)
		return 0;
	
	if(pwd->m_uid == 1)//服务器模式
	{
		pwd->SetWindowTextA("已建立游戏、等待其他人加入");
		CSocket listSock,lisRecvSock;

		if(!listSock.Create(pwd->m_ServerPort))
		{
			pwd->GetSocketError();
			return -1;
		}
		if(!lisRecvSock.Create(pwd->m_ServerPortRecv))
		{
			pwd->GetSocketError();
			return -1;
		}
		
		lisRecvSock.Listen(3);
		listSock.Listen(3);

		if(!listSock.Accept(pwd->SendSock))//给客户端发送数据socket连接
		{
			pwd->GetSocketError();
			return -1;
		}
		MsgPack msp;
		msp.type = ALLOT_ID;
		msp.data.uid = pwd->m_uid+1;
		//分配客户ID
		if(SOCKET_ERROR==pwd->SendSock.Send(&msp,sizeof(MsgPack)))
		{
			pwd->GetSocketError();
			return -1;
		}
		if(!lisRecvSock.Accept(pwd->RecvSock))//从客户端接收数据socket连接
		{
			pwd->GetSocketError();
			return -1;
		}

		
	}
	else//客户端模式
	{
		MsgPack msp;
		pwd->SendSock.Create();
		pwd->RecvSock.Create();
		//从服务器接收数据的socket
		if(!pwd->RecvSock.Connect(pwd->hostAddrSock,m_ServerPort))
		{
			pwd->GetSocketError();
			return -1;
		}
		//从服务器接收ID分配的数据
		if(SOCKET_ERROR==pwd->RecvSock.Receive(&msp,sizeof(MsgPack)))
		{
			pwd->GetSocketError();
			return -1;
		}
		if(msp.type == ALLOT_ID)
		{
			pwd->m_uid = msp.data.uid;
		}
		//发送数据到服务器的socket
		if(!pwd->SendSock.Connect(pwd->hostAddrSock,m_ServerPortRecv))
		{
			pwd->GetSocketError();
			return -1;
		}
		msp.type = JOIN_GAME;
		//给服务器发送加入游戏的确认信息
		if(SOCKET_ERROR==pwd->RecvSock.Send(&msp,sizeof(MsgPack)))
		{
			pwd->GetSocketError();
			return -1;
		}
		pwd->SetWindowTextA("已连接上服务器");
	}
	pwd->SetWindowTextA("开始游戏!");
	
	pwd->m_gameStart = true;
	pwd->m_receving = true;
	while (pwd->m_appruning)//开始接收游戏数据
	{
		MsgPack msp;
		
		if(pwd->RecvSock.Receive(&msp,sizeof(MsgPack)) == SOCKET_ERROR)
		{
			pwd->GetSocketError();
			return -1;
		}

		if (msp.type == MOVE)
		{
			UINT winner = pwd->PlaceRecv(msp.data.PD.x,msp.data.PD.y,msp.data.PD.uid);
			if(0==winner)
			{
				continue;
			}
			else if (winner==pwd->m_uid)
			{
				pwd->MessageBox("你赢了!!");
				pwd->CleanGrid();
				return 0;
			}
			else
			{
				pwd->MessageBox("你输了");
				pwd->CleanGrid();
				return 0;
			}
		}
		else if (msp.type == QUIT_GAME)
		{
			return 0;
		}
	}
	return 0;
}


 

源代码下载: http://download.csdn.net/download/jokers_i/4223218

你可能感兴趣的:(C/C++,MFC,游戏开发)