Statistics and testing of seven threads and servers in the Android RakNet Series
Introduction
A thread is a single sequential control flow in a program. A relatively independent and schedulable execution unit in a process is the basic unit for Independent System Scheduling and CPU allocation, which refers to the scheduling unit of the running program. It is called multithreading.
The thread is re-encapsulated in Raknet, and the class is RakThread.
A good server is reflected in the maximum rate of memory usage, but not every programmer can grasp the memory. What should we check if there is a problem on the server? Logs.
Logs are the server's black box, which counts the server's information.
Raknet also provides server connection statistics.
Thread details class definition
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);#elsestatic int Create( void* start_address( void* ), void *arglist, int priority=0);#endif};
Provides multiple platforms
#if defined(_XBOX) || defined(X360) #elif defined(_WIN32)#include "WindowsIncludes.h"#include
#if !defined(_WIN32_WCE)#include
#endif#else#include
#endif
Test
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);elsepeer2->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();elsep=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);elsepeer2->DeallocatePacket(p);} RakSleep(500);}return 0;}
Effect
Statistical details
Class Definition
<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD48cHJlIGNsYXNzPQ = "brush: java;"> // 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 errorscase 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;};
Test
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;}
Effect
Summary
This example tests Raknet threads and statistics, but to be familiar with threads, you also need to master the following knowledge:
Thread stack model and thread variables, thread state conversion, thread synchronization and lock, thread interaction, thread scheduling-sleep, thread scheduling-priority, thread scheduling-concession thread Scheduling-merge, thread scheduling-daemon thread, thread synchronization-synchronization method, thread synchronization-synchronization block, concurrent collaboration-producer consumer model, concurrent collaboration-deadlock, volatile keywords, thread pool, threads with returned values, locks, semaphores, blocking queues, blocking stacks, condition variables, atomic weights, barrier.
It's hard for you to master this knowledge.