⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.cpp

📁 Visual C++ 游戏开发与设计实例 源代码(所有)
💻 CPP
字号:

#include <winsock2.h>
#include <windows.h>
#include "struct.h"
#include "pool.h"
#include "netmsg.h"


HANDLE		iocp;
SOCKET		slisten;
int			sport = 5500;

CInordPool<OVERLAPPEDEX>	olexPool;
CInordPool<PLAYER>			playerPool;
GAMETABLE					gTable;

void Notice( int num, ... );
void Notice( LPCTSTR head, int msgid );

//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
void WSAErrorTrigger( int error, LPCTSTR msg ) {
	switch (error)
	{
	case WSA_IO_PENDING:
		break;

	case WSAENOBUFS:
//		Notice(defstr,"No buffers!");
		break;

	case WSANOTINITIALISED:
//		Notice(defstr,"Need Startup()!");
		break;

	case WSAEINVAL:
//		Notice(defstr,"Call listen() first!");
		break;

	case WSAENOTSOCK:
//		Notice(defstr,"Not a socket!");
		break;

	default:;
//		Notice(defstr);
	}
}

//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
bool InitServer()
{
	WSADATA			wsd;
	sockaddr_in		local;

	// initiates use of Ws2_32.dll 
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
		return false;

	// create listening socket
	slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (slisten == SOCKET_ERROR) {
		WSACleanup();
    	return false;
	}

	// bind address and port
	local.sin_addr.s_addr = htonl(INADDR_ANY);
	local.sin_family	  = AF_INET;
	local.sin_port		  = htons(sport);
	if(bind(slisten,(struct sockaddr *)&local,
		sizeof(local)) == SOCKET_ERROR) {
		closesocket( slisten );
		WSACleanup();
		return false;
	}
	
	// set nonblock property
	//	if(ioctlsocket(slisten,FIONBIO,&ul)== SOCKET_ERROR)
	//		return false;

	// create iocp, and add listen socket on it
	iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
	if ( !iocp ) {
		closesocket( slisten );
		WSACleanup();
		return false;
	}

	// initialize pools
	if ( !olexPool.InitPool(0) || !playerPool.InitPool(16) ) {
		closesocket( slisten );
		WSACleanup();
		return false;
	}
	ZeroMemory( &gTable, sizeof(GAMETABLE) );

	// start listening
	if ( listen(slisten,SOMAXCONN) != 0 ) {
		closesocket( slisten );
		WSACleanup();
		return false;
	}

	Notice(1, "Server start successfully!");
	return true;
}

//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
void TerminateServer() {
	closesocket( slisten );
	WSACleanup();
}


//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
void RecvMsg( LPOVERLAPPEDEX lpolex ) 
{
	DWORD	flags = 0;

	lpolex->op = OP_READ;
	lpolex->wbuf.buf = lpolex->buf;
	lpolex->wbuf.len = DEFBUFFERSIZE;
	ZeroMemory(&(lpolex->ol),sizeof(OVERLAPPED));

//	int ret = 
	WSARecv((lpolex->socket),&(lpolex->wbuf),1,&(lpolex->bytes),
		&flags,&(lpolex->ol),NULL);
//	if ( ret == SOCKET_ERROR  ) {
//		ret = WSAGetLastError();
//		WSAErrorTrigger(ret, "RecvError:");
//	}
}


//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
void SendMsg( int msg, SOCKET socket, LPVOID param, int size )
{
	int				length;
	int				*ibuf;
	LPOVERLAPPEDEX	lpolex = olexPool.GetUsable();

	ibuf = (int *)(lpolex->buf);
	ibuf[0] = msg;
	if( param ) {
		length = DEFBUFFERSIZE - sizeof(int)*2;
		if ( size < length )
			length = size;
		memcpy( &ibuf[2], param, length );
	} 
	else
		length = 0;

	ibuf[1] = length;

	lpolex->ppla = NULL;
	lpolex->socket = socket;
	lpolex->op = OP_WRITE;
	lpolex->wbuf.buf = lpolex->buf;
	lpolex->wbuf.len = length + sizeof(int)*2;
	ZeroMemory(&(lpolex->ol),sizeof(OVERLAPPED));

//	int ret = 
	WSASend(socket, &(lpolex->wbuf), 1, &(lpolex->bytes), 0,
		&(lpolex->ol), NULL );
//	if ( ret == SOCKET_ERROR  ) {
//		ret = WSAGetLastError();
//		WSAErrorTrigger(ret, "RecvError:");
//	}

	// !! DEBUG
	//Notice(temp);
}

//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
void SendMsgToTable( int msg, GAMETABLE table, LPVOID param, int size ) {
	for ( int i=0; i<MAXPLAYER; i++ ) {
		if ( table.players[i] == NULL )
			break;
		SendMsg( msg, table.players[i]->socket, param, size );
	}
}

//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
void SendMsgToOther( int msg, GAMETABLE table,int except, LPVOID param, int size ) {
	for ( int i=0; i<MAXPLAYER; i++ ) {
		if ( i != except && table.players[i] != NULL ) 
			SendMsg( msg, table.players[i]->socket, param, size );
	}
}
//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
DWORD WINAPI AcceptThread( LPVOID pParam ) {
	sockaddr_in		client;
	int				size;
	SOCKET			ret;
	OVERLAPPEDEX	*lpolex;
	
	while(true) {	
		size = sizeof(sockaddr_in);
		ret = accept(slisten,(sockaddr *)&client,&size);

		if(ret != INVALID_SOCKET)
		{
			Notice(2, "Connect:", inet_ntoa(client.sin_addr));
			lpolex = olexPool.GetUsable();

			if ( lpolex )
			{
				CreateIoCompletionPort((HANDLE)ret, iocp, NULL, 0);
				// initiate communication
				lpolex->socket = ret;
				RecvMsg( lpolex );
			} 
			else {
				closesocket( ret );
				// Notice(2, "NULLOLEX:", inet_ntoa(client.sin_addr));
			}
		} 
		else {	// accept error
			ret = WSAGetLastError();
			WSAErrorTrigger(ret, TEXT("AcceptErr: "));
		}
	}
	return 0;
}


//-----------------------------------------------------------------------------
// Name: 
// Desc:
//-----------------------------------------------------------------------------
DWORD WINAPI WorkerThread(LPVOID pParam) {
	ULONG_PTR		ckey;
	OVERLAPPED		*pol;
    OVERLAPPEDEX	*polex;
//	LPGAMETABLE		ptable;
    DWORD           BytesTransferred;
	int				ret;
	int				*ibuf;

	while(true) {	
		ret = GetQueuedCompletionStatus(iocp, &BytesTransferred,
			&ckey,&pol,INFINITE);

		// structure-hack-a-roo
		polex = CONTAINING_RECORD(pol, OVERLAPPEDEX, ol);

		// Operation failed
		if ( ret == 0) {	
			// May a remote player has been disconnected.
			int				size = sizeof(sockaddr_in);
			sockaddr_in		client;
			getpeername(polex->socket,(sockaddr *)&client,&size);
			Notice(2, "Discont:", inet_ntoa(client.sin_addr));
			
			// remove the seat
			for ( int i=0; i<gTable.current; i++ ) {
				if ( gTable.players[i] == polex->ppla ) {
					if ( i > 0 )
						gTable.players[i-1]->next = polex->ppla->next;
					break;
				}
			}
			for ( ; i<gTable.current-1; i++ )
				gTable.players[i] = gTable.players[i+1];
			gTable.current--;

			// Pool recycle
			playerPool.Recycle( polex->ppla );
			olexPool.Recycle( polex );

			continue;
		}

		// Operation succeeded
		switch (polex->op) {

		case OP_READ:
			ibuf = (int *)(polex->wbuf.buf);
			switch ( ibuf[0] ) {

			// allocate a player seat and a table
			case NETMSGTK_ASKGROUPINFO:		
				Notice( "AskGroup: ", ibuf[2] );
				polex->ppla = playerPool.GetUsable();
				polex->ppla->seat = gTable.current;
				gTable.players[gTable.current] = polex->ppla;
				gTable.players[gTable.current]->socket = polex->socket;
				SendMsg( NETMSGTK_ANSWERSEATINFO, polex->socket, 
					&gTable.current, sizeof(int) );
				Notice( "AnswerSeat: ", gTable.current );

				// set list pointer
				polex->ppla->next = NULL;
				if ( gTable.current > 0 ) {
					gTable.players[gTable.current-1]->next = polex->ppla;
					SendMsgToOther( NETMSGTK_MOREPLAYER, gTable, gTable.current,
						&gTable.current, sizeof(int) );
				}
				
				if ( ++gTable.current == MAXPLAYER )
					SendMsgToTable( NETMSGTK_GAMEREADY, gTable, NULL, 0 );
				break;

			case NETMSGTK_PLAYERREADY:
				if ( ++gTable.counter == MAXPLAYER ) {
					SendMsgToTable( NETMSGTK_GAMESTART, gTable, NULL, 0 );
					// initialize table's food creator
					gTable.food.exsit = false;
					gTable.food.existnum = DEFFOODEXFRAME;
					gTable.food.notexistnum = DEFFOODNOTEXFRAME;
					gTable.food.counter = DEFFOODNOTEXFRAME;
					// reset table counter
					gTable.counter = 0;
				}
				break;

			case NETMSGTK_CMDINFO:
				if ( gTable.food.counter-- <= 0 ) {
					if ( gTable.food.exsit ) {		// delete
						gTable.food.counter = gTable.food.notexistnum;
						SendMsgToTable( NETMSGTK_CMDFOODDELETE, gTable, NULL, 0 );
					} else {				// create
						gTable.food.counter = gTable.food.existnum;
						int	foodparam[3];
						foodparam[0] = rand() % FOOD_MAX;
						foodparam[1] = rand() % 608;		// !TODO: CONVERT with different sizes
						foodparam[2] = rand() % 608;
						SendMsgToTable( NETMSGTK_CMDFOODCREATE, gTable, foodparam, sizeof(int)*3 );
					}
					gTable.food.exsit = !gTable.food.exsit;
				}

				// 
				SendMsgToOther( NETMSGTK_CMDINFO, gTable, polex->ppla->seat, ibuf+2, ibuf[1] );
				break;

			case NETMSGTK_TEAMVICTORY:
//				Notice( "Victory: ", ibuf[2] );
				SendMsgToTable( NETMSGTK_TEAMVICTORY, gTable, ibuf+2, ibuf[1] );
				break;
			}
//			Notice(2, "RecvMsg: ", polex->wbuf.buf+8);
			RecvMsg( polex );
			break;


		case OP_WRITE:
			// Recycle
			olexPool.Recycle( polex );
			break;
		}
	}
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -