当前位置: 代码迷 >> Android >> Android RakNet 系列之7 线程和服务端统计测试
  详细解决方案

Android RakNet 系列之7 线程和服务端统计测试

热度:52   发布时间:2016-04-28 02:46:49.0
Android RakNet 系列之七 线程和服务端统计测试
简介

线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

Raknet中重新封装了线程,类为:RakThread。

一个好的服务端体现在最大率使用内存,但并不是每一个程序员都可以把握好内存,一旦服务端出现了问题,我们查什么?日志。

日志就是服务端的黑匣子,统计了服务端的信息。

Raknet也提供了服务端连接统计。

线程详情
类定义

class RAK_DLL_EXPORT RakThread{public:	/// Create a thread, simplified to be cross platform without all the extra junk	/// To then start that thread, call RakCreateThread(functionName, arguments);	/// \param[in] start_address Function you want to call	/// \param[in] arglist Arguments to pass to the function	/// \return 0=success. >0 = error code	/*	nice value 	Win32 Priority	-20 to -16 	THREAD_PRIORITY_HIGHEST	-15 to -6 	THREAD_PRIORITY_ABOVE_NORMAL	-5 to +4 	THREAD_PRIORITY_NORMAL	+5 to +14 	THREAD_PRIORITY_BELOW_NORMAL	+15 to +19 	THREAD_PRIORITY_LOWEST	*/#if defined(_WIN32_WCE)	static int Create( LPTHREAD_START_ROUTINE start_address, void *arglist, int priority=0);#elif defined(_XBOX) || defined(X360)                                                                                              #elif defined(_WIN32)	static int Create( unsigned __stdcall start_address( void* ), void *arglist, int priority=0);#else	static int Create( void* start_address( void* ), void *arglist, int priority=0);#endif};

提供了多个平台

#if defined(_XBOX) || defined(X360)                                                  #elif defined(_WIN32)#include "WindowsIncludes.h"#include <stdio.h>	#if !defined(_WIN32_WCE)	#include <process.h>	#endif#else#include <pthread.h>#endif

测试

	for (i=0; i< 10; i++)	{		count[i]=i;		RakNet::RakThread::Create(&ProducerThread, count+i);	}	for (; i < 20; i++)	{		count[i]=i;		RakNet::RakThread::Create(&ConsumerThread, count+i );	}
RAK_THREAD_DECLARATION(ProducerThread){	char i = *((char *) arguments);	char out[2];	out[0]=ID_USER_PACKET_ENUM;	out[1]=i;	while (endThreads==false)	{		printf("Thread %i writing...\n", i);		if (i&1)			peer1->Send(out, 2, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);		else			peer2->Send(out, 2, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);		printf("Thread %i done writing\n", i);		RakSleep(500);	}		return 0;}RAK_THREAD_DECLARATION(ConsumerThread){	char i = *((char *) arguments);	RakNet::Packet *p;	while (endThreads==false)	{		printf("Thread %i reading...\n", i);		if (i&1)			p=peer1->Receive();		else			p=peer2->Receive();		printf("Thread %i done reading...\n", i);		if (p)		{			if (p->data[0]==ID_USER_PACKET_ENUM)				printf("Got data from thread %i\n", p->data[1]);			if (i&1)				peer1->DeallocatePacket(p);			else				peer2->DeallocatePacket(p);		}        RakSleep(500);			}	return 0;}

效果如图:



统计详情

类定义

// Connects, sends data over time, disconnects, repeatclass Client{	public:		Client()		{			peer = RakNet::RakPeerInterface::GetInstance();		}		~Client()		{			RakNet::RakPeerInterface::DestroyInstance(peer);		}		void Startup(void)		{			RakNet::SocketDescriptor socketDescriptor;	

{			peer->CloseConnection(peer->GetSystemAddressFromIndex(0),true,0);			isConnected=false;		}		void Update(RakNet::TimeMS curTime)		{			Packet *p = peer->Receive();			while (p)			{				switch (p->data[0])				{				case ID_CONNECTION_REQUEST_ACCEPTED:					printf("ID_CONNECTION_REQUEST_ACCEPTED\n");					isConnected=true;					break;					// print out errors				case ID_CONNECTION_ATTEMPT_FAILED:					printf("Client Error: ID_CONNECTION_ATTEMPT_FAILED\n");					isConnected=false;					break;				case ID_ALREADY_CONNECTED:					printf("Client Error: ID_ALREADY_CONNECTED\n");					break;				case ID_CONNECTION_BANNED:					printf("Client Error: ID_CONNECTION_BANNED\n");					break;				case ID_INVALID_PASSWORD:					printf("Client Error: ID_INVALID_PASSWORD\n");					break;				case ID_INCOMPATIBLE_PROTOCOL_VERSION:					printf("Client Error: ID_INCOMPATIBLE_PROTOCOL_VERSION\n");					break;				case ID_NO_FREE_INCOMING_CONNECTIONS:					printf("Client Error: ID_NO_FREE_INCOMING_CONNECTIONS\n");					isConnected=false;					break;				case ID_DISCONNECTION_NOTIFICATION:					//printf("ID_DISCONNECTION_NOTIFICATION\n");					isConnected=false;					break;				case ID_CONNECTION_LOST:					printf("Client Error: ID_CONNECTION_LOST\n");					isConnected=false;					break;				}				peer->DeallocatePacket(p);				p = peer->Receive();						}			if (curTime>nextSendTime && isConnected)			{				peer->Send((const char*)&randomData,RANDOM_DATA_SIZE,HIGH_PRIORITY,RELIABLE_ORDERED,0,RakNet::UNASSIGNED_SYSTEM_ADDRESS,true);				nextSendTime=curTime+30;			}		}		bool isConnected;		RakPeerInterface *peer;		RakNet::TimeMS nextSendTime;};

// Just listens for ID_USER_PACKET_ENUM and validates its integrityclass Server{	public:		Server()		{			peer = RakNet::RakPeerInterface::GetInstance();		}		~Server()		{			RakNet::RakPeerInterface::DestroyInstance(peer);		}		void Start(void)		{			RakNet::SocketDescriptor socketDescriptor;			socketDescriptor.port=(unsigned short) SERVER_PORT;			bool b = peer->Startup((unsigned short) NUM_CLIENTS,&socketDescriptor,1)==RakNet::RAKNET_STARTED;			RakAssert(b);			peer->SetMaximumIncomingConnections(NUM_CLIENTS);		}		unsigned ConnectionCount(void) const		{			unsigned i,count;			for (i=0,count=0; i < NUM_CLIENTS;i++)				if (peer->GetSystemAddressFromIndex(i)!=RakNet::UNASSIGNED_SYSTEM_ADDRESS)					count++;			return count;		}		void Update(RakNet::TimeMS curTime)		{			Packet *p = peer->Receive();			while (p)			{				switch (p->data[0])				{				case ID_CONNECTION_LOST:				case ID_DISCONNECTION_NOTIFICATION:				case ID_NEW_INCOMING_CONNECTION:					printf("Connections = %i\n", ConnectionCount());					break;				case ID_USER_PACKET_ENUM:					{						if (memcmp(p->data, randomData, RANDOM_DATA_SIZE)!=0)						{							printf("Bad data on server!\n");						}						break;					}				}				peer->DeallocatePacket(p);				p = peer->Receive();			}		}				RakPeerInterface *peer;};
测试

int main(void){	Client clients[NUM_CLIENTS];	Server server;//	int clientIndex;	int mode;	printf("Connects many clients to a single server.\n");	printf("Difficulty: Intermediate\n\n");	printf("Run as (S)erver or (C)lient or (B)oth? ");	char ch = getche();	static char *remoteIP="94.198.81.195";	static char *localIP="127.0.0.1";	if (ch=='s' || ch=='S')		mode=0;	else if (ch=='c' || ch=='c')	{		mode=1;		remoteIPAddress=remoteIP;	}	else	{		mode=2;		remoteIPAddress=localIP;	}	printf("\n");	unsigned i;	randomData[0]=ID_USER_PACKET_ENUM;	for (i=0; i < RANDOM_DATA_SIZE-1; i++)		randomData[i+1]=i;	if (mode==0 || mode==2)	{		server.Start();		printf("Started server\n");	}	if (mode==1 || mode==2)	{		printf("Starting clients...\n");		for (i=0; i < NUM_CLIENTS; i++)			clients[i].Startup();		printf("Started clients\n");		printf("Connecting clients...\n");		for (i=0; i < NUM_CLIENTS; i++)			clients[i].Connect();		printf("Done.\n");	}		RakNet::TimeMS endTime = RakNet::GetTimeMS()+60000*5;	RakNet::TimeMS time = RakNet::GetTimeMS();	while (time < endTime)	{		if (mode==0 || mode==2)			server.Update(time);		if (mode==1 || mode==2)		{			for (i=0; i < NUM_CLIENTS; i++)				clients[i].Update(time);		}		if (kbhit())		{			char ch = getch();			if (ch==' ')			{				FILE *fp;				char text[2048];				if (mode==0 || mode==2)				{					printf("Logging server statistics to ServerStats.txt\n");					fp=fopen("ServerStats.txt","wt");					for (i=0; i < NUM_CLIENTS; i++)					{						RakNetStatistics *rssSender;						rssSender=server.peer->GetStatistics(server.peer->GetSystemAddressFromIndex(i));						StatisticsToString(rssSender, text, 3);						fprintf(fp,"==== System %i ====\n", i+1);						fprintf(fp,"%s\n\n", text);					}					fclose(fp);				}				if (mode==1 || mode==2)				{					printf("Logging client statistics to ClientStats.txt\n");					fp=fopen("ClientStats.txt","wt");					for (i=0; i < NUM_CLIENTS; i++)					{						RakNetStatistics *rssSender;						rssSender=clients[i].peer->GetStatistics(clients[i].peer->GetSystemAddressFromIndex(0));						StatisticsToString(rssSender, text, 3);						fprintf(fp,"==== Client %i ====\n", i+1);						fprintf(fp,"%s\n\n", text);					}					fclose(fp);				}			}				if (ch=='q' || ch==0)				break;		}		time = RakNet::GetTimeMS();		RakSleep(30);	}	if (mode==0 || mode==2)		server.peer->Shutdown(0);	if (mode==1 || mode==2)		for (i=0; i < NUM_CLIENTS; i++)			clients[i].peer->Shutdown(0);	printf("Test completed");	return 0;}

效果如图:



总结

本例测试了Raknet线程和统计,但要熟练掌握线程,还需要掌握如下知识:
线程栈模型与线程的变量、线程状态的转换、线程的同步与锁、线程的交互、线程的调度-休眠 、线程的调度-优先级、线程的调度-让步、线程的调度-合并、线程的调度-守护线程、线程的同步-同步方法、线程的同步-同步块 、并发协作-生产者消费者模型、并发协作-死锁、volatile关键字、线程池、有返回值的线程、锁、信号量、阻塞队列、阻塞栈、条件变量、原子量、障碍器。
掌握了这些知识,你不牛逼也难了。
  相关解决方案