www.pudn.com > Five_QT_by_CT.rar > HallMaster.cpp


#include "HallMaster.h"

HallMaster::HallMaster(QWidget *parent, char *name)
	:QWidget(parent, name)
{
	mGamefaceOpened=false;
	mOnline=false;
	CreateSockFD();
	mTimer =new QTimer(this, 0);
	connect(mTimer, SIGNAL(timeout()), this, SLOT(sReceiver())); 
	mOpID=QString("-1");
}


HallMaster::~HallMaster()
{
	
}

//接收数据的函数,由QTimer类的定时器每50ms驱动一次
void HallMaster:: sReceiver()
{
	int recvnum,val;
	val=fcntl(mSockFD, F_GETFL, 0);
	fcntl(mSockFD,F_SETFL, val|O_NONBLOCK);
	int i=0;
	while(i++<10)
	{

  
		recvnum=recvfrom(mSockFD, mRevBuf, BUF_LEN,0,0,0);
  	 	if(recvnum==-1)
   	 	{
     			//perror("recvmsg");

     			
   	 	}
  	 	
		else
		{
			printf("int receiver received!%s\n",mRevBuf);

			//通知Disposer处理信息
			Disposer();
		}
	}
	mTimer->start( 50 );
		
}




//将Message 格式的数据结构以udp数据包形式发送到dstaddr
int HallMaster::Sender(Message msg,struct sockaddr_in dstaddr )
{
 	 int sockfd,sendnum,len; 
	char buffer[BUF_LEN];
	len=mPackDisposer.MsgPacker(msg,buffer);


	sockfd=socket(AF_INET,SOCK_DGRAM,0);
  if(sockfd==-1)
   {
    perror("socket");
    exit(1);
   }
 
	sendnum =sendto(mSockFD,buffer,len,0,(struct sockaddr *)&dstaddr,sizeof(struct sockaddr));
   	if(sendnum<0)
	{
		perror("sendto");
	}
	
	buffer[sendnum]='\0';
	printf("send, %s  to %s, %d\n",buffer,inet_ntoa(dstaddr.sin_addr),ntohs(dstaddr.sin_port));

return 0;

}



//创建套接字,收发使用同一个socket fd
bool HallMaster::CreateSockFD()
{
	
	
	int sockfd;   
	
 	//准备连接
 	sockfd=socket(AF_INET,SOCK_DGRAM,0);
 	if(sockfd==-1)
   	{
    		perror("socket");
    		
   	}
	mSockFD=sockfd;
	
}




int HallMaster::SetServerAddr(QString ip)
{
	
	mServerAddr.sin_family=AF_INET;
	mServerAddr.sin_port=htons(1500);
	inet_pton(AF_INET,ip.ascii() ,&mServerAddr.sin_addr);	
}





//Runner是驱动本类工作的函数
int HallMaster::Runner()
{
	if(mOnline)
	{
		printf("still online!!!\n");
		return 1;
	}
	mTimer->start( 50 );
  	mMsgToSend.mID=QString("0000");
  	mMsgToSend.mRequest=QString("login");
 		mMsgToSend.mContent=QString("F");
        Sender(mMsgToSend, mServerAddr);
  	
}



//分发器, 根据收到数据的请求调用相应函数处理,本函数由Receiver()调用
int HallMaster::Disposer()
{
	Message msg;

	mPackDisposer.MsgUnPacker(mMsgRecvd,mRevBuf);
	

	//收到登录回复,得到ID
	if(!mMsgRecvd.mRequest.compare(QString("login")))
	{
		mMyID=mMsgRecvd.mContent;
		mOnline=true;
		
		msg.mRequest=QString("hmyid");
		msg.mContent=mMsgRecvd.mContent;
		emit sendmsgtomain(msg);
		
	}

	//收到更新信息
	else if(!mMsgRecvd.mRequest.compare(QString("update")))
		UpdatePlayerTable();
	
	

	//更新结束消息
	else if(!mMsgRecvd.mRequest.compare(QString("endupdate")))
	{	
		
		emit updatehall(); //一次性更新界面
		return 5;
          //5表示结束更新
	}


	//receive invitation, pass it to mMain to decide;
	else if(!mMsgRecvd.mRequest.compare(QString("invite")))
	{
		msg.mRequest="hreplyinvite";
		emit sendmsgtomain( msg);

	}

	//收到邀请回复,邀请信息在进入对局界面后按下棋盘下方"Start"时发出,"Start"按下时,先修改自己的状态为"Waiting",再发邀请
	else if(!mMsgRecvd.mRequest.compare(QString("reinvite:agree")))
	{
		
		//记录对方addr,便于发送聊天信息,游戏数据
		int index= mMsgRecvd.mID.toInt();
		QString addr, port;
		addr=mPlayerTable[index].mAddr;
		port=mPlayerTable[index].mPort;
		ConvertQStrToSockaddr(addr, port, mOpAddr);
		
		//对局相关,交给Main处理
		msg.mRequest=QString("hagreeinvite");
		emit sendmsgtomain(msg);
		
	}
	
	//对方发来落子的坐标
	else if(!mMsgRecvd.mRequest.compare(QString("putchess")))
	{	
		//对局相关,交给Main处理
		msg.mRequest = QString("hputchess");
		msg.mContent = mMsgRecvd.mContent;
		emit sendmsgtomain( msg );
	}


	//服务器发来换座(坐下)的回复
	else if(!mMsgRecvd.mRequest.compare(QString("rechangeseat")))
	{	
		//判断成功于否
		printf("sitdown result in Content :%s\n",mMsgRecvd.mRequest.ascii());
		if(mMsgRecvd.mContent.compare(QString("succeed"))==0)

		//显示 交给Main下来完成,
		{	
			msg.mRequest=QString("hchangeseat");
			HandleSeatchanged(msg);
			
			
		}
		else
			{printf("change seat failed!\n");}//提示失败
	}
	
	//对方发来聊天信息
	else if(!mMsgRecvd.mRequest.compare(QString("chat")))
	{	
		msg.mRequest = QString("recvchat");
		msg.mContent = mMsgRecvd.mContent;
		emit sendmsgtomain(msg);
	}

	else 
	{
		printf("unknown request!\n");
	}
	return 123;//该返回值无特定意义
}


//获取第i号player的id
QString HallMaster::getPlayerID( int i )
{
	if(i>0&&i0&&i0&&i0&&i0)
		return mPlayerTable[i].mDeskNumber;
	else 
		return QString("0");
}


//更新playertable
int HallMaster::UpdatePlayerTable()
{
	//还原出一条PlayerTableNode
	PlayerTableNode node;
        char tempt[BUF_LEN];
	strncpy(tempt,mMsgRecvd.mContent.ascii(),mMsgRecvd.mContent.length());
	mPackDisposer.TableUnPacker(node,tempt);
	

	//根据ID找到相应Player
	int index;
	index=node.mPlayerID.toInt();
	
	
	//替换其中信息,为保持desktable一致性,先删除desktable的旧信息 
	int k=mPlayerTable[index].mDeskNumber.toInt();
	QString lastside=mPlayerTable[index].mSide;
	if(k!=0)
	{
		
		if(lastside.compare("white")==0)
			mDeskTable[k].mWhiteID="-1";
		else
			mDeskTable[k].mBlackID="-1";
		
	}	

	mPlayerTable[index].mPlayerID=node.mPlayerID;
	mPlayerTable[index].mPlayerState=node.mPlayerState;
	mPlayerTable[index].mPlayerOpID=node.mPlayerOpID;
	mPlayerTable[index].mAddr=node.mAddr;
	mPlayerTable[index].mPort=node.mPort;
	mPlayerTable[index].mDeskNumber=node.mDeskNumber;
	mPlayerTable[index].mSide=node.mSide;


	//更新mDeskTable,保持同步
	 k=node.mDeskNumber.toInt(); //player所在桌号,0表示不在桌上
	if(k==0)
		return 0;
	else
		//判断方向
		if(node.mSide.compare("white")==0)
			mDeskTable[k].mWhiteID=node.mPlayerID;
		else
			mDeskTable[k].mBlackID=node.mPlayerID;

	
	
	//根据mPlayerTable向mMain发送myDesk的桌位信息
	index=mMyID.toInt();
	k=mPlayerTable[index].mDeskNumber.toInt();
	if(k==0)
		return 0;

	Message msg;
	msg.mRequest=QString("hupdatedesk");
	msg.mContent=mDeskTable[k].mWhiteID;
	msg.mContent2=mDeskTable[k].mBlackID;
	emit sendmsgtomain(msg);
	
	return 0;
}


//向同一桌的对手发送邀请游戏信息
void HallMaster::HandleSendInvite()
{	
	//找到自己的桌位得到对方ID
	int index=mMyID.toInt();
	int dsknum=mPlayerTable[index].mDeskNumber.toInt();
	QString id;
	if(mDeskTable[dsknum].mWhiteID.compare(mMyID)==0)//找对方的id
		id=mDeskTable[dsknum].mBlackID;
	else
		id=mDeskTable[dsknum].mWhiteID;

	
	//根据ID查找对方地址 待改进
	int i;
	for(i=2; i=MAX_PLAYER)
		printf("id not found!\n");

	

	
	struct sockaddr_in dstaddr;
	if(ConvertQStrToSockaddr( mPlayerTable[i].mAddr ,mPlayerTable[i].mPort ,dstaddr )==false)
	{
		printf("convertqstrtosockaddr failed!\n");
		return;
	} 
	
	//发送"invite"请求
	Message msg;
	msg.mID=mMyID;
	msg.mRequest=QString("invite");
	msg.mContent=id;
	
	
	Sender(msg, dstaddr);
	
}


//将QString表示的IP地址和端口号转换成struct sockaddr, 协议一致为AF_INET
bool HallMaster::ConvertQStrToSockaddr(QString addr, QString port, struct sockaddr_in &dstaddr)
{	
		
	if(addr.ascii()==NULL||port.ascii()==NULL)
		return false;
	
	dstaddr.sin_family=AF_INET;
	if(inet_pton(AF_INET, addr.ascii(), &dstaddr.sin_addr)<=0)
	{
		perror("inet_pton");
		return false;
	}
	dstaddr.sin_port=htons(port.toInt());

	return true;
	
}

//处理mMain::mChessBoard发送来的同意下棋的请求,将同意下棋邀请信息回复邀请方
void HallMaster::HandleAgreeInvite()
{
	Message msg;
	//得到邀请方ID,并查询对方地址
	QString id=mMsgRecvd.mID;
	int index=id.toInt();
	QString addr=mPlayerTable[index].mAddr;
	QString port=mPlayerTable[index].mPort;
	
	//发送回复
		
	struct sockaddr_in dstaddr;
	msg.mID=mMyID;
	msg.mRequest=QString("reinvite:agree");
	msg.mContent="agree";
		
	ConvertQStrToSockaddr(addr,port,dstaddr);
	Sender(msg,dstaddr);
	//记录对方addr
	ConvertQStrToSockaddr(addr, port, mOpAddr);
	
}



//本方下棋后传来落子坐标,在此处理
void HallMaster::HandleChessput(Message msg)
{
	
	//将坐标发送给对方
	Message msgtosend;
	msgtosend.mID=mMyID;
	msgtosend.mRequest=QString("putchess");
	msgtosend.mContent=msg.mContent+QString("#")+msg.mContent2+QString("#");
	Sender(msgtosend, mOpAddr);
			
}


//坐下或换座时向服务器发送请求坐下(换座)的请求
void HallMaster:: HandleSendSitdown(QString dsknum, QString side)
{
	
	Message msg;
	msg.mID=mMyID;
	msg.mRequest=QString("changeseat");
	msg.mContent=dsknum+QString("&")+side+QString("&");
	Sender(msg, mServerAddr);
}

//收到server回复,坐下(换座)成功,通知mMain
void HallMaster:: HandleSeatchanged(Message msg)
{
	//get myside and mydesknumber
	int index=mMyID.toInt();
	int k=mPlayerTable[index].mDeskNumber.toInt();
	if(k<=0)
		return ;
	QString side;
	if(mDeskTable[k].mWhiteID.compare(mMyID)==0)
		side=QString("white");
	else
		side=QString("black");
	msg.mRequest=QString("hchangeseat");
	msg.mContent=side;
	emit sendmsgtomain(msg);
	emit showgameface();
}



//向对方发送聊天内容
void HallMaster::HandleSendChat(Message msg)
{
	msg.mID=mMyID;
	msg.mRequest=QString("chat");
	Sender(msg, mOpAddr);
}



//退出大厅时的处理函数
void HallMaster:: sonquit()
{
	//check current state decide if it is valid to quit
	if(mGamefaceOpened)
		printf("please close gamewindow!\n");

	//send request "quit" to server
	Message msg;
	msg.mID=mMyID;
	msg.mRequest=QString("quit");
	
	Sender(msg, mServerAddr);
	
	//close and quit
	emit quithall();
}


//处理内部消息的分发器
void HallMaster::sdisposemsg(Message msg)
{
	QString req=msg.mRequest;

	//mMain::mChessBoard发来同意邀请下棋的请求
	if(!req.compare("bagreeinvite"))
	{
		HandleAgreeInvite();
	}

	//mMain::mChessBoard发来邀请下棋的请求,转发给对方
	else if(!req.compare("bsendinvite"))
	{
		printf("in hallmaster::disposemsg, going to handle bsendinvite\n");
		HandleSendInvite();
	}
	//mMain::mChessBoard 发来落子消息
	else if(!req.compare("bchessput"))
	{
		HandleChessput(msg);
	}
	
	//Hall 发来坐下请求,转发给服务器
	else if(!req.compare("hallsitdown"))
	{
		HandleSendSitdown(msg.mContent, msg.mContent2);
	}

	//mMain::mChatBox发来聊天信息
	else if(!req.compare("cchat"))
	{
		HandleSendChat(msg);
	}

	//Hall 发来设置服务器地址的消息
	else if(!req.compare("hallsetserveraddr"))
	{
		SetServerAddr( msg.mContent);
	}
	else 
		printf("hallmaster::disposemsg, unknown request! %s\n",msg.mRequest.ascii());
}