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 + -
显示快捷键?