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