网络通信部分放在了独立的线程中处理,因为使用的是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