handbeas服务器dlg.cpp
来自「手机开发环境BREW实例」· C++ 代码 · 共 601 行
CPP
601 行
// HandBeas服务器Dlg.cpp : implementation file
//
#include "stdafx.h"
#include "HandBeas服务器.h"
#include "HandBeas服务器Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CHandBeasDlg dialog
CHandBeasDlg::CHandBeasDlg(CWnd* pParent /*=NULL*/)
: CDialog(CHandBeasDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CHandBeasDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
memset(m_pbtGrid, 0, sizeof(m_pbtGrid));
memset(m_phSocket, 0, sizeof(m_phSocket));;
memset(m_pbRecvPack, 0, sizeof(m_pbRecvPack));
memset(m_ptCurPlayer, 0, sizeof(m_ptCurPlayer));
memset(m_psPack4Send, 0, sizeof(m_psPack4Send));
m_hListen = NULL;
m_iThreadCount = 0;
memset(m_piExp, 0, sizeof(m_piExp));
}
CHandBeasDlg::~CHandBeasDlg()
{
this->m_bExitThread = TRUE;
int iMaxWait = 20;
while(m_iThreadCount && (iMaxWait > 0))
{
Sleep(100);
iMaxWait--;
}
}
void CHandBeasDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CHandBeasDlg)
DDX_Control(pDX, IDC_LIST_LOG, m_ctlListLog);
DDX_Control(pDX, IDC_LIST_EXP, m_ctlListExp);
DDX_Control(pDX, IDC_STATIC_IMAGE, m_ctlmage);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CHandBeasDlg, CDialog)
//{{AFX_MSG_MAP(CHandBeasDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CHandBeasDlg message handlers
//服务线程
DWORD WINAPI ThreadServer(LPVOID lpPara)
{
CHandBeasDlg* pDlg = (CHandBeasDlg*)lpPara;
pDlg->m_iThreadCount++;
DWORD dwRet; //用来存储返回值
fd_set sFDS4Read;
timeval sTimeval4Timeout;
FD_ZERO(&sFDS4Read);
sTimeval4Timeout.tv_sec = 1;
sTimeval4Timeout.tv_usec = 0;
int iPutStarCount = 0;
BOOL bGotStar = TRUE;//是否已经有人把星吃了
while(!pDlg->m_bExitThread)
{
//接收所有玩家的数据包
for(int i = 1; i < MAX_PLAYERS; i++)
{
if(pDlg->m_pbRecvPack[i] && pDlg->m_phSocket[i])
{//需要接收数据包且socket存在
FD_ZERO(&sFDS4Read);
FD_SET(pDlg->m_phSocket[i], &sFDS4Read);
dwRet = select(0, &sFDS4Read, NULL, NULL, &sTimeval4Timeout);
if((dwRet == SOCKET_ERROR) || (dwRet == 0))
{//socket出错,或1秒还没有等到数据包,就关闭这个socket
pDlg->RemovePlayer(i);
}
//程序运行到这里,说明有一个数据包等待接收
dwRet = recv(pDlg->m_phSocket[i], (char*)(&(pDlg->m_psPack4Send[i])), sizeof(pDlg->m_psPack4Send[i]), 0);
if(dwRet == SOCKET_ERROR || !dwRet)
{//socket出错
pDlg->RemovePlayer(i);
}
}
}
//收完数据包后进行统一处理
for(i = 1; i < MAX_PLAYERS; i++)
{
if(pDlg->m_pbRecvPack[i] && pDlg->m_phSocket[i])
{//需要接收数据包且socket存在
//先布雷
if(pDlg->m_psPack4Send[i].btBomb)
{
pDlg->m_pbtGrid[pDlg->m_ptCurPlayer[i].x][pDlg->m_ptCurPlayer[i].y] |= 0x40;
}
if( *((WORD*)pDlg->m_psPack4Send[i].pbtPack4Send) )
{//位置有变动, 更新位置
POINT ptOld = pDlg->m_ptCurPlayer[i];
pDlg->m_ptCurPlayer[i].x += ((char)pDlg->m_psPack4Send[i].pbtPack4Send[1]);
pDlg->m_ptCurPlayer[i].y += ((char)pDlg->m_psPack4Send[i].pbtPack4Send[0]);
//检查走到这个新位置后的情况
if( (pDlg->m_ptCurPlayer[i].x >= 0) && (pDlg->m_ptCurPlayer[i].x < MAX_GRID) &&
(pDlg->m_ptCurPlayer[i].y >= 0) && (pDlg->m_ptCurPlayer[i].y < MAX_GRID) &&
(!(pDlg->m_pbtGrid[pDlg->m_ptCurPlayer[i].x][pDlg->m_ptCurPlayer[i].y] & 0x3F)) )
{//不会出界,也不会碰到其它玩家
if(pDlg->m_pbtGrid[pDlg->m_ptCurPlayer[i].x][pDlg->m_ptCurPlayer[i].y] & 0x80)
{//吃星
pDlg->m_piExp[i]++;
bGotStar = TRUE;
pDlg->OnGetStar(i);
}else if(pDlg->m_pbtGrid[pDlg->m_ptCurPlayer[i].x][pDlg->m_ptCurPlayer[i].y] & 0x40)
{//吃雷
pDlg->m_piExp[i]--;
pDlg->OnGetBomb(i);
}else
{//什么也没有发生,走到一个空位置
}
//去掉以前的位置
pDlg->m_pbtGrid[ptOld.x][ptOld.y] &= 0xC0;
//设置新的位置
pDlg->m_pbtGrid[pDlg->m_ptCurPlayer[i].x][pDlg->m_ptCurPlayer[i].y] = i;
}else
{//还原坐标
pDlg->m_ptCurPlayer[i] = ptOld;
}
}
}
}
//在给玩家显示视图以前,布下星
if( iPutStarCount >= PUTSTAR_INTER_TIME )
{
if(bGotStar)
{
iPutStarCount = 0;
if(!pDlg->PutStar())
{//还未布下星
iPutStarCount = PUTSTAR_INTER_TIME / 3;//加速
}else
{
bGotStar = FALSE;
}
}
}else
{
iPutStarCount++;
}
//统一处理完后再把这个视图发给所有在线玩家
for(i = 1; i < MAX_PLAYERS; i++)
{
if(pDlg->m_phSocket[i])
{//有效socket,玩家在线
if(!pDlg->m_pbRecvPack[i])
{
pDlg->m_pbRecvPack[i] = TRUE;//下一次循环时允许接收来自这个玩家的数据包
}
dwRet = send(pDlg->m_phSocket[i], (char*)(pDlg->m_pbtGrid), sizeof(pDlg->m_pbtGrid), 0);//strlen(pContent) + 1, 0);
if((dwRet == SOCKET_ERROR) || (dwRet != sizeof(pDlg->m_pbtGrid)))
{
pDlg->RemovePlayer(i);
}
}
}
//显示
pDlg->RefurbishScreen();
Sleep(10);
}//while()
goto L_ThreadServer_Exit;
L_ThreadServer_Exit:
pDlg->m_iThreadCount--;
TRACE("ThreadServer 退出!\n");
return 0;
}
//帧听
DWORD WINAPI ThreadListen(LPVOID lpPara)
{
CHandBeasDlg* pDlg = (CHandBeasDlg*)lpPara;
pDlg->m_iThreadCount++;
fd_set sFDS4Read;
timeval sTimeout;
DWORD dwRet;
struct sockaddr_in addrRemote;
SOCKET hAccept;
int iAddrLength = sizeof(struct sockaddr_in); //addrRemote的大小
FD_ZERO(&sFDS4Read);
sTimeout.tv_sec = 0;
sTimeout.tv_usec = 500000;
while(!pDlg->m_bExitThread)
{
FD_SET(pDlg->m_hListen, &sFDS4Read);
dwRet = select(0, &sFDS4Read, NULL, NULL, &sTimeout);
if(dwRet == SOCKET_ERROR)
{//select时出错
AfxMessageBox("TheadListen Select 出错!");
goto L_ThreadListen_Exit;
}
if(!dwRet)
{//没有要accept的socket,继续
// Sleep(100);
continue;
}
//程序运行到这里已经有一个socket等待被接受
//先接受
hAccept = accept(pDlg->m_hListen, (struct sockaddr *)(&addrRemote), &iAddrLength);
//再插到数据里
for(int i = 1; i < MAX_PLAYERS; i++)
{
if(!pDlg->m_phSocket[i])
{//找到一个空位
pDlg->m_pbRecvPack[i] = FALSE;//先不要检查它发来的数据包,因为服务器必须先向手机发包
pDlg->m_phSocket[i] = hAccept;//插入Socket
break;
}
}
if( i >= MAX_PLAYERS )
{//找不到空位
closesocket(hAccept);
}else
{
pDlg->m_piExp[i] = 0;//积分为0
if(!(pDlg->SetOrigPos(i)))//设置起始位置
{//没有空地方了
closesocket(hAccept);
}
}
}
L_ThreadListen_Exit:
pDlg->m_iThreadCount--;
TRACE("ThreadListen 退出!\n");
return 0;
}
BOOL CHandBeasDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
CClientDC dc(this);
m_dcBomb.CreateCompatibleDC(&dc);
m_dcStar.CreateCompatibleDC(&dc);
m_dcMem.CreateCompatibleDC(&dc);
CBitmap bmp1, bmp2, bmp3;
bmp1.LoadBitmap(IDB_BOMB);
bmp2.LoadBitmap(IDB_STAR);
bmp3.CreateCompatibleBitmap(&dc, BLOCK_SIZE * MAX_GRID, BLOCK_SIZE * MAX_GRID);
m_dcBomb.SelectObject(&bmp1);
m_dcStar.SelectObject(&bmp2);
m_dcMem.SelectObject(&bmp3);
// this->SetTimer(ID_TIMER1, 500, NULL);
//开服务
//求出IP值
DWORD dwIP = inet_addr(SERVER_IP);
if(dwIP == INADDR_NONE)
{//失败
AfxMessageBox("帧听失败!");
return FALSE;
}
//从windows申请Socket
this->m_hListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if(m_hListen == INVALID_SOCKET)
{//失败
AfxMessageBox("帧听失败!");
return FALSE;
}
//绑定 bind
sockaddr_in addrLocal;
memset(&addrLocal, 0, sizeof(struct sockaddr_in));
addrLocal.sin_addr.S_un.S_addr = dwIP;
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons((unsigned short)SERVER_PORT);
if(bind(m_hListen, (struct sockaddr*)&addrLocal, sizeof(struct sockaddr_in)))
{//失败
AfxMessageBox("帧听失败!");
return FALSE;
}
//帧听端口
if(listen(m_hListen, SOMAXCONN) == SOCKET_ERROR)
{//失败
AfxMessageBox("帧听失败!");
return FALSE;
}
//开线程
this->m_bExitThread = FALSE;
if(CreateThread(0, 0, ThreadListen, this, 0, NULL) == NULL)
{
AfxMessageBox("开线程失败!");
return FALSE;
}
if(CreateThread(0, 0, ThreadServer, this, 0, NULL) == NULL)
{
AfxMessageBox("开线程失败!");
return FALSE;
}
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CHandBeasDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}else
{
/* CDialog::OnPaint();
CWindowDC dc(&m_ctlmage);
dc.BitBlt(0, 0, BLOCK_SIZE * MAX_GRID, BLOCK_SIZE * MAX_GRID, &m_dcMem, 0, 0, SRCCOPY);*/
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CHandBeasDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CHandBeasDlg::DrawStar(int x, int y)
{
this->m_dcMem.BitBlt(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, &m_dcStar, 0, 0, SRCCOPY);
}
void CHandBeasDlg::DrawBomb(int x, int y)
{
this->m_dcMem.BitBlt(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, &m_dcBomb, 0, 0, SRCCOPY);
}
void CHandBeasDlg::DrawPlayer(int x, int y, BYTE btContent)
{
//求出颜色值
BYTE pbtRet[4];//ret[0]-R ret[1]-G ret[2]-B
*((DWORD*)pbtRet) = 0;
//红
if(btContent & 1)
{
pbtRet[0] = 0xFF;
}
if(btContent & 8)
{
pbtRet[0] -= (0xFF / 2);
}
//绿
if(btContent & 2)
{
pbtRet[1] = 0xFF;
}
if(btContent & 16)
{
pbtRet[1] -= (0xFF / 2);
}
//蓝
if(btContent & 4)
{
pbtRet[2] = 0xFF;
}
if(btContent & 32)
{
pbtRet[2] -= (0xFF / 2);
}
//pbtRet[4];//ret[0]-R ret[1]-G ret[2]-B
CPen cPen(PS_SOLID, 1, RGB(pbtRet[0], pbtRet[1], pbtRet[2]));
CBrush cBrush(RGB(pbtRet[0], pbtRet[1], pbtRet[2]));
CPen *pOldPen = m_dcMem.SelectObject(&cPen);
CBrush *pOldBrush = m_dcMem.SelectObject(&cBrush);
m_dcMem.Ellipse(BLOCK_SIZE * x, BLOCK_SIZE * y, BLOCK_SIZE * x + BLOCK_SIZE, BLOCK_SIZE * y + BLOCK_SIZE);
m_dcMem.SelectObject(pOldPen);
m_dcMem.SelectObject(pOldBrush);
}
//这个字节是个星吗?
BOOL IsStar(BYTE btContent)
{
#ifdef _DEBUG
if(btContent & 0x80)
{
ASSERT(btContent == 0x80);
}
#endif
return (btContent & 0x80);
}
//这个字节内容是个雷吗?
BOOL IsBomb(BYTE btContent)
{
return (btContent & 0x40);
}
//这个字节内容是个玩家吗?一个网格上可以同时出现玩家和雷
BOOL IsPlayer(BYTE btContent)
{
return (((unsigned char)(btContent & 0x3F)) > 0);
}
void CHandBeasDlg::RefurbishScreen()
{
this->m_dcMem.FillSolidRect(0, 0, BLOCK_SIZE * MAX_GRID, BLOCK_SIZE * MAX_GRID, RGB(0, 0, 0));
//画出网格内容
for(int x = 0; x < MAX_GRID; x++)
{
for(int y = 0; y < MAX_GRID; y++)
{
if(IsStar(m_pbtGrid[x][y]))
{//是星
DrawStar(x, y);
}else
{
if(IsBomb(m_pbtGrid[x][y]))
{//有雷
DrawBomb(x, y);
}
if(IsPlayer(m_pbtGrid[x][y]))
{//有玩家在上面,看来是这个玩布下的
DrawPlayer(x, y, m_pbtGrid[x][y]);
}
}
}
}
//最后显示出来
CWindowDC dc(&m_ctlmage);
dc.BitBlt(0, 0, BLOCK_SIZE * MAX_GRID, BLOCK_SIZE * MAX_GRID, &m_dcMem, 0, 0, SRCCOPY);
}
//同步调用
BOOL CHandBeasDlg::SetOrigPos(int iIndex)
{
for(int x = 0; x < MAX_GRID; x++)
{
for(int y = 0; y < MAX_GRID; y++)
{
if( !this->m_pbtGrid[x][y] )
{
this->m_ptCurPlayer[iIndex].x = x;
this->m_ptCurPlayer[iIndex].y = y;
m_pbtGrid[x][y] = iIndex;
return TRUE;
}
}
}
return FALSE;
}
//同步调用
BOOL CHandBeasDlg::PutStar()
{
int x, y;
int iMax = 100;
do{
if( (iMax--) <= 0 )
{
break;
}
x = (MAX_GRID - 1) * rand() / 32767;
y = (MAX_GRID - 1) * rand() / 32767;
}while(this->m_pbtGrid[x][y]);
if( !this->m_pbtGrid[x][y] )
{
this->m_pbtGrid[x][y] = 0x80;
return TRUE;
}else
{
return FALSE;
}
}
//同步调用
void CHandBeasDlg::RemovePlayer(int iIndex)
{
closesocket(m_phSocket[iIndex]);
m_pbRecvPack[iIndex] = FALSE;
m_phSocket[iIndex] = NULL;
m_pbtGrid[m_ptCurPlayer[iIndex].x][m_ptCurPlayer[iIndex].y] = 0;
}
void CHandBeasDlg::OnGetStar(int iIndex)
{
CString str;
str.Format("Player%d吃星,积分增为%d", iIndex, this->m_piExp[iIndex]);
this->m_ctlListLog.InsertString(-1, str);
m_ctlListLog.SetCurSel(m_ctlListLog.GetCount() - 1);
m_ctlListExp.ResetContent();
for(int i = 1; i < MAX_PLAYERS; i++)
{
if(this->m_phSocket[i])
{
str.Format("Player%d: %d分", i, this->m_piExp[i]);
m_ctlListExp.InsertString(-1, str);
}
}
}
void CHandBeasDlg::OnGetBomb(int iIndex)
{
CString str;
str.Format("Player%d吃雷,积分降为%d", iIndex, this->m_piExp[iIndex]);
this->m_ctlListLog.InsertString(-1, str);
m_ctlListLog.SetCurSel(m_ctlListLog.GetCount() - 1);
m_ctlListExp.ResetContent();
for(int i = 1; i < MAX_PLAYERS; i++)
{
if(this->m_phSocket[i])
{
str.Format("Player%d: %d分", i, this->m_piExp[i]);
m_ctlListExp.InsertString(-1, str);
}
}
m_ctlListExp.SetCurSel(0);
}
void CHandBeasDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if(nIDEvent == ID_TIMER1)
{
this->RefurbishScreen();
}
CDialog::OnTimer(nIDEvent);
m_ctlListExp.SetCurSel(0);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?