CloudClientSample.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include "MessageIdentifiers.h"
  11. #include "BitStream.h"
  12. #include "CloudClient.h"
  13. #include "RakPeerInterface.h"
  14. #include "RakSleep.h"
  15. #include <stdlib.h>
  16. void PrintHelp(void)
  17. {
  18. printf("CloudClient as a directory server.\n");
  19. printf("Usage:\n");
  20. printf("CloudClient.exe ServerAddress [Port]\n\n");
  21. printf("Parameters:\n");
  22. printf("ServerAddress - Any server in the cloud.\n");
  23. printf("Port - Server listen port. Default is 60000\n");
  24. printf("Example:\n");
  25. printf("CloudServer.exe test.dnsalias.net 60000\n\n");
  26. }
  27. #define CLOUD_CLIENT_PRIMARY_KEY "CC_Sample_PK"
  28. void UploadInstanceToCloud(RakNet::CloudClient *cloudClient, RakNet::RakNetGUID serverGuid);
  29. void GetClientSubscription(RakNet::CloudClient *cloudClient, RakNet::RakNetGUID serverGuid);
  30. void GetServers(RakNet::CloudClient *cloudClient, RakNet::RakNetGUID serverGuid);
  31. int main(int argc, char **argv)
  32. {
  33. const char *DEFAULT_SERVER_ADDRESS="test.dnsalias.net";
  34. const unsigned short DEFAULT_SERVER_PORT=60000;
  35. const char *serverAddress;
  36. unsigned short serverPort;
  37. #ifndef _DEBUG
  38. // Only use DEFAULT_SERVER_ADDRESS for debugging
  39. if (argc<2)
  40. {
  41. PrintHelp();
  42. return false;
  43. }
  44. #endif
  45. if (argc<2) serverAddress=DEFAULT_SERVER_ADDRESS;
  46. else serverAddress=argv[1];
  47. if (argc<3) serverPort=DEFAULT_SERVER_PORT;
  48. else serverPort=atoi(argv[2]);
  49. // ---- RAKPEER -----
  50. RakNet::RakPeerInterface *rakPeer;
  51. rakPeer=RakNet::RakPeerInterface::GetInstance();
  52. static const unsigned short clientLocalPort=0;
  53. RakNet::SocketDescriptor sd(clientLocalPort,0); // Change this if you want
  54. RakNet::StartupResult sr = rakPeer->Startup(1,&sd,1); // Change this if you want
  55. rakPeer->SetMaximumIncomingConnections(0); // Change this if you want
  56. if (sr!=RakNet::RAKNET_STARTED)
  57. {
  58. printf("Startup failed. Reason=%i\n", (int) sr);
  59. return 1;
  60. }
  61. RakNet::CloudClient cloudClient;
  62. rakPeer->AttachPlugin(&cloudClient);
  63. RakNet::ConnectionAttemptResult car = rakPeer->Connect(serverAddress, serverPort, 0, 0);
  64. if (car==RakNet::CANNOT_RESOLVE_DOMAIN_NAME)
  65. {
  66. printf("Cannot resolve domain name\n");
  67. return 1;
  68. }
  69. printf("Connecting to %s...\n", serverAddress);
  70. bool didRebalance=false; // So we only reconnect to a lower load server once, for load balancing
  71. RakNet::Packet *packet;
  72. while (1)
  73. {
  74. for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive())
  75. {
  76. switch (packet->data[0])
  77. {
  78. case ID_CONNECTION_LOST:
  79. printf("Lost connection to server.\n");
  80. return 1;
  81. case ID_CONNECTION_ATTEMPT_FAILED:
  82. printf("Failed to connect to server at %s.\n", packet->systemAddress.ToString(true));
  83. return 1;
  84. case ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY:
  85. case ID_OUR_SYSTEM_REQUIRES_SECURITY:
  86. case ID_PUBLIC_KEY_MISMATCH:
  87. case ID_INVALID_PASSWORD:
  88. case ID_CONNECTION_BANNED:
  89. // You won't see these unless you modified CloudServer
  90. printf("Server rejected the connection.\n");
  91. return 1;
  92. case ID_INCOMPATIBLE_PROTOCOL_VERSION:
  93. printf("Server is running an incompatible RakNet version.\n");
  94. return 1;
  95. case ID_NO_FREE_INCOMING_CONNECTIONS:
  96. printf("Server has no free connections\n");
  97. return 1;
  98. case ID_IP_RECENTLY_CONNECTED:
  99. printf("Recently connected. Retrying.");
  100. rakPeer->Connect(serverAddress, serverPort, 0, 0);
  101. break;
  102. case ID_CONNECTION_REQUEST_ACCEPTED:
  103. printf("Connected to server.\n");
  104. UploadInstanceToCloud(&cloudClient, packet->guid);
  105. GetClientSubscription(&cloudClient, packet->guid);
  106. GetServers(&cloudClient, packet->guid);
  107. break;
  108. case ID_CLOUD_GET_RESPONSE:
  109. {
  110. RakNet::CloudQueryResult cloudQueryResult;
  111. cloudClient.OnGetReponse(&cloudQueryResult, packet);
  112. unsigned int rowIndex;
  113. const bool wasCallToGetServers=cloudQueryResult.cloudQuery.keys[0].primaryKey=="CloudConnCount";
  114. printf("\n");
  115. if (wasCallToGetServers)
  116. printf("Downloaded server list. %i servers.\n", cloudQueryResult.rowsReturned.Size());
  117. else
  118. printf("Downloaded client list. %i clients.\n", cloudQueryResult.rowsReturned.Size());
  119. unsigned short connectionsOnOurServer=65535;
  120. unsigned short lowestConnectionsServer=65535;
  121. RakNet::SystemAddress lowestConnectionAddress;
  122. for (rowIndex=0; rowIndex < cloudQueryResult.rowsReturned.Size(); rowIndex++)
  123. {
  124. RakNet::CloudQueryRow *row = cloudQueryResult.rowsReturned[rowIndex];
  125. if (wasCallToGetServers)
  126. {
  127. unsigned short connCount;
  128. RakNet::BitStream bsIn(row->data, row->length, false);
  129. bsIn.Read(connCount);
  130. printf("%i. Server found at %s with %i connections\n", rowIndex+1, row->serverSystemAddress.ToString(true), connCount);
  131. unsigned short connectionsExcludingOurselves;
  132. if (row->serverGUID==packet->guid)
  133. connectionsExcludingOurselves=connCount-1;
  134. else
  135. connectionsExcludingOurselves=connCount;
  136. // Find the lowest load server (optional)
  137. if (packet->guid==row->serverGUID)
  138. {
  139. connectionsOnOurServer=connectionsExcludingOurselves;
  140. }
  141. else if (connectionsExcludingOurselves < lowestConnectionsServer)
  142. {
  143. lowestConnectionsServer=connectionsExcludingOurselves;
  144. lowestConnectionAddress=row->serverSystemAddress;
  145. }
  146. }
  147. else
  148. {
  149. printf("%i. Client found at %s", rowIndex+1, row->clientSystemAddress.ToString(true));
  150. if (row->clientGUID==rakPeer->GetMyGUID())
  151. printf(" (Ourselves)");
  152. RakNet::BitStream bsIn(row->data, row->length, false);
  153. RakNet::RakString clientData;
  154. bsIn.Read(clientData);
  155. printf(" Data: %s", clientData.C_String());
  156. printf("\n");
  157. }
  158. }
  159. // Do load balancing by reconnecting to lowest load server (optional)
  160. if (didRebalance==false && wasCallToGetServers && cloudQueryResult.rowsReturned.Size()>0 && connectionsOnOurServer>lowestConnectionsServer)
  161. {
  162. printf("Reconnecting to lower load server %s\n", lowestConnectionAddress.ToString(false));
  163. rakPeer->CloseConnection(packet->guid, true);
  164. // Wait for the thread to close, otherwise will immediately get back ID_CONNECTION_ATTEMPT_FAILED because no free outgoing connection slots
  165. // Alternatively, just call Startup() with 2 slots instead of 1
  166. RakSleep(500);
  167. rakPeer->Connect(lowestConnectionAddress.ToString(false), lowestConnectionAddress.GetPort(), 0, 0);
  168. didRebalance=true;
  169. }
  170. cloudClient.DeallocateWithDefaultAllocator(&cloudQueryResult);
  171. }
  172. break;
  173. case ID_CLOUD_SUBSCRIPTION_NOTIFICATION:
  174. {
  175. bool wasUpdated;
  176. RakNet::CloudQueryRow cloudQueryRow;
  177. cloudClient.OnSubscriptionNotification(&wasUpdated, &cloudQueryRow, packet, 0 );
  178. if (wasUpdated)
  179. printf("New client at %s\n", cloudQueryRow.clientSystemAddress.ToString(true));
  180. else
  181. printf("Lost client at %s\n", cloudQueryRow.clientSystemAddress.ToString(true));
  182. cloudClient.DeallocateWithDefaultAllocator(&cloudQueryRow);
  183. }
  184. break;
  185. }
  186. }
  187. // Any additional client processing can go here
  188. RakSleep(30);
  189. }
  190. RakNet::RakPeerInterface::DestroyInstance(rakPeer);
  191. return 0;
  192. }
  193. void UploadInstanceToCloud(RakNet::CloudClient *cloudClient, RakNet::RakNetGUID serverGuid)
  194. {
  195. RakNet::CloudKey cloudKey(CLOUD_CLIENT_PRIMARY_KEY,0);
  196. RakNet::BitStream bs;
  197. bs.Write("Hello World"); // This could be anything such as player list, game name, etc.
  198. cloudClient->Post(&cloudKey, bs.GetData(), bs.GetNumberOfBytesUsed(), serverGuid);
  199. }
  200. void GetClientSubscription(RakNet::CloudClient *cloudClient, RakNet::RakNetGUID serverGuid)
  201. {
  202. RakNet::CloudQuery cloudQuery;
  203. cloudQuery.keys.Push(RakNet::CloudKey(CLOUD_CLIENT_PRIMARY_KEY,0),_FILE_AND_LINE_);
  204. cloudQuery.subscribeToResults=true; // Causes ID_CLOUD_SUBSCRIPTION_NOTIFICATION
  205. cloudClient->Get(&cloudQuery, serverGuid);
  206. }
  207. void GetServers(RakNet::CloudClient *cloudClient, RakNet::RakNetGUID serverGuid)
  208. {
  209. RakNet::CloudQuery cloudQuery;
  210. cloudQuery.keys.Push(RakNet::CloudKey("CloudConnCount",0),_FILE_AND_LINE_); // CloudConnCount is defined at the top of CloudServerHelper.cpp
  211. cloudQuery.subscribeToResults=false;
  212. cloudClient->Get(&cloudQuery, serverGuid);
  213. }
粤ICP备19079148号