fork download
  1. #include <iostream>
  2. #include <fstream>
  3. #include <string>
  4. #include <sstream>
  5. #include <allegro5/allegro.h>
  6. #include <allegro5/allegro_font.h>
  7. #include <allegro5/allegro_ttf.h>
  8.  
  9. #include "SDL_net.h"
  10.  
  11. ALLEGRO_DISPLAY *display;
  12. ALLEGRO_EVENT_QUEUE *event_queue;
  13. ALLEGRO_TIMER *timer;
  14. ALLEGRO_EVENT ev;
  15. ALLEGRO_FONT *font;
  16.  
  17. Uint8 * dotQuad; // Listening IP
  18. const unsigned short PORT = 1337; // The port our server will listen for incoming connections on
  19. const unsigned short BUFFER_SIZE = 512; // Size of our message buffer
  20. const unsigned short MAX_SOCKETS = 500; // Max number of sockets
  21. const unsigned short MAX_CLIENTS = MAX_SOCKETS - 1; // Max number of clients in our socket set (-1 because we place the servers listening socket as the first socket in the set)
  22.  
  23. // Messages we recieve from or send back to any connecting(ed) client
  24. const std::string SERVER_NOT_FULL = "OK";
  25. const std::string SERVER_FULL = "SERVER FULL";
  26.  
  27. std::string text = "";
  28. std::string text2 = "";
  29.  
  30. bool serverRunning = true;
  31. bool redraw = false;
  32. int clientCount = 0; // Count of how many clients are currently connected to the server.
  33.  
  34. int main(int argc, char **argv) {
  35. std::ofstream file("Errors.txt");
  36. file << "Program initialized" << std::endl;
  37.  
  38. if (!al_init()) {
  39. file << "Failed to initialize Allegro!" << std::endl;
  40. return -1;
  41. }
  42.  
  43. //Create ourself a window
  44. display = al_create_display(640, 480);
  45. if (!display) {
  46. file << "Failed to initialize Display!" << std::endl;
  47. al_destroy_display(display);
  48. return -1;
  49. }
  50.  
  51. event_queue = al_create_event_queue();
  52. if (!event_queue) {
  53. file << "Failed to initialize Event Queue!" << std::endl;
  54. al_destroy_event_queue(event_queue);
  55. return -1;
  56. }
  57.  
  58. timer = al_create_timer(1.0 / 60.0);
  59. if (!timer) {
  60. file << "Failed to initialize Timer!" << std::endl;
  61. al_destroy_timer(timer);
  62. return -1;
  63. }
  64.  
  65. if (SDLNet_Init() == -1) {
  66. file << "Failed to initialize SDL_Net!" << std::endl;
  67. return -1;
  68. }
  69.  
  70. IPaddress serverIP; // The ip of the server (0.0.0.0 - any IP)
  71. TCPsocket serverSocket; // The server socket that clients will use to coonect to us
  72. TCPsocket clientSocket[MAX_CLIENTS]; // An array of sockets for the clients.
  73. bool isSocketFree[MAX_CLIENTS]; // An array of flags to keep track of which client sockets are free
  74.  
  75. char buffer[BUFFER_SIZE]; // Array of characters used to store the messages we receive
  76. int receivedByteCount = 0; // A variable to keep track of how many bytes (i.e. characters) we need to read for any given incoming message i.e. the size of the incoming data
  77. std::string clientcount_string = "none";
  78. std::stringstream myString;
  79.  
  80. // Create a socket set with enough space to store our desired number of connections (sockets)
  81. SDLNet_SocketSet socketSet = SDLNet_AllocSocketSet(MAX_SOCKETS);
  82. if (!socketSet) {
  83. file << "Failed to allocate Socket set!" << std::endl;
  84. }
  85. else
  86. {
  87. file << "Socket set allocated with size: " << MAX_SOCKETS << ", of which " << MAX_CLIENTS << " are available for use by clients." << std::endl;
  88. }
  89.  
  90. // Initialize all the sockets (i.e. blank them ready for use!)
  91. for (int i = 0; i < MAX_CLIENTS; i++) {
  92. clientSocket[i] = NULL;
  93. isSocketFree[i] = TRUE; // Set all our sockets to be free (i.e. available for use for new client connections)
  94. }
  95.  
  96. al_init_font_addon();
  97. al_init_ttf_addon();
  98.  
  99. font = al_load_font("data/fonts/bookosb.ttf", 24, 0);
  100.  
  101. al_register_event_source(event_queue, al_get_display_event_source(display));
  102. al_register_event_source(event_queue, al_get_timer_event_source(timer));
  103.  
  104. al_start_timer(timer);
  105.  
  106. int hostResolved = SDLNet_ResolveHost(&serverIP, NULL, PORT);
  107.  
  108. if (hostResolved == -1) {
  109. file << "Failed to resolve the server host!" << std::endl;
  110. text = "Server not started.";
  111. }
  112. else {
  113. dotQuad = (Uint8*)&serverIP.host;
  114.  
  115. file << "Successfully resolved host to IP: " << (unsigned short)dotQuad[0] << "." << (unsigned short)dotQuad[1] << "." << (unsigned short)dotQuad[2] << "." << (unsigned short)dotQuad[3] << ":" << PORT << std::endl;
  116. text = "Server started.";
  117. }
  118.  
  119. serverSocket = SDLNet_TCP_Open(&serverIP);
  120.  
  121. if (!serverSocket) {
  122. file << "Failed to open the server socket." << std::endl;
  123. text2 = "Failed to open socket.";
  124. }
  125. else {
  126. file << "Successfully created the server socket." << std::endl;
  127. text2 = "Waiting for clients.";
  128. }
  129.  
  130. // Add our server socket to the socket set
  131. SDLNet_TCP_AddSocket(socketSet, serverSocket);
  132.  
  133. file << "Waiting for clients..." << std::endl;
  134.  
  135. do {
  136. // Check for activity on the entire socket set. The second parameter is the number of milliseconds to wait for.
  137. // For the wait-time, 0 means do not wait (high CPU!), -1 means wait for up to 49 days (no, really), and any other number is a number of milliseconds, i.e. 5000 means wait for 5 seconds
  138.  
  139. int numActiveSockets = SDLNet_CheckSockets(socketSet, 0);
  140.  
  141. if (numActiveSockets != 0) {
  142. file << "There are currently " << numActiveSockets << " socket(s) with data to be processed." << std::endl;
  143. }
  144.  
  145. // Check if our server socket has received any daya
  146. // Note: SocketReady can only be called on a socket which is part of a set and that has CheckSocket called on it (the set, that is)
  147. // SDLNet_SocketRead returns non-zero for activity, and zero is returned for no activity. Which is a bit bass-ackwards IMHO, but there you go.
  148. int serverSocketActivity = SDLNet_SocketReady(serverSocket);
  149.  
  150. //file << "Just checked client number " << clientNumber << " and received activity status is: " << clientSocketActivity << endl;
  151.  
  152. // If there is activity on our server socket (i.e. a client has transmitted data to us) then...
  153. if (serverSocketActivity != 0) {
  154.  
  155. // If we have room for more clients
  156. if (clientCount < MAX_CLIENTS) {
  157. // Find the first free socket in our array of client sockets
  158. int freeSpot = -99;
  159. for (int i = 0; i < MAX_CLIENTS; i++) {
  160. if (isSocketFree[i]) {
  161. file << "Found a free spot at element: " << i << std::endl;
  162. isSocketFree[i] = false; // Set the socket to be taken
  163. freeSpot = i; // Keep the location to add our connection at the index in the array of client sockets
  164. break; // Break out straight away
  165. }
  166. }
  167.  
  168. // Accept the client connection and then...
  169. clientSocket[freeSpot] = SDLNet_TCP_Accept(serverSocket);
  170.  
  171. // ... Add the new client socket to the socket set (o.e. the list of sockets we check for activity)
  172. SDLNet_TCP_AddSocket(socketSet, clientSocket[freeSpot]);
  173.  
  174. // Increase our client count
  175. clientCount++;
  176.  
  177. // Send a message to the client saying "OK" to indicate the incoming connection has been accepted
  178. strcpy_s(buffer, SERVER_NOT_FULL.c_str());
  179. int msgLength = strlen(buffer) + 1;
  180. SDLNet_TCP_Send(clientSocket[freeSpot], (void *)buffer, msgLength);
  181.  
  182. file << "Client connected, there are now " << clientCount << " client(s) connected." << std::endl;
  183. }
  184. else { // If we don't have room for new clients..
  185. file << "Maximum client count reached - rejecting client connection!" << std::endl;
  186.  
  187. // Accept the client connection to clear it form the incoming connections list
  188. TCPsocket tempSock = SDLNet_TCP_Accept(serverSocket);
  189.  
  190. // Send a message to the client saying "Server is full" to tell the client to go away
  191. strcpy_s(buffer, SERVER_FULL.c_str());
  192. int msgLength = strlen(buffer) + 1;
  193. SDLNet_TCP_Send(tempSock, (void *)buffer, msgLength);
  194.  
  195. // Shutdown, disconnect, and close the socket to the client
  196. SDLNet_TCP_Close(tempSock);
  197. }
  198. } // End of if server socket has activity check
  199.  
  200. // Loop to check all the possible client sockets for activity
  201. for (int clientNumber = 0; clientNumber < MAX_CLIENTS; clientNumber++) {
  202. // If the socket is ready (i.e. it has data we can read)... (SDLNet_SocketReady returns non-zero if there is activity on the socket, and zero if there is no activity)
  203. int clientSocketActivity = SDLNet_SocketReady(clientSocket[clientNumber]);
  204.  
  205. // If there is any activity on the client socket...
  206. if (clientSocketActivity != 0) {
  207. // Check if the client socket has transmitted any data by reading from the socket and placing it in the buffer character array
  208. receivedByteCount = SDLNet_TCP_Recv(clientSocket[clientNumber], buffer, BUFFER_SIZE);
  209.  
  210. // If there's activity, but we didn't read anything from the client socket, then the client has disconnected...
  211. if (receivedByteCount <= 0)
  212. {
  213. //...so output a suitable message and then...
  214. file << "Client " << clientNumber << " disconnected." << std::endl << std::endl;
  215.  
  216. //... remove the socket from the socket set, then close and reset the socket ready for re-use and finally...
  217. SDLNet_TCP_DelSocket(socketSet, clientSocket[clientNumber]);
  218. SDLNet_TCP_Close(clientSocket[clientNumber]);
  219. clientSocket[clientNumber] = NULL;
  220.  
  221. // ...free up their slot so it can be reused...
  222. isSocketFree[clientNumber] = true;
  223.  
  224. // ...and decrement the count of connected clients.
  225. clientCount--;
  226.  
  227. file << "Server is now connected to: " << clientCount << " client(s)." << std::endl << std::endl;
  228. }
  229. else // If we read some data from the client socket...
  230. {
  231. // Output the message the server received to the screen
  232. file << "Received: >>>> " << buffer << " from client number: " << clientNumber << std::endl;
  233.  
  234. // Send message to all other connected clients
  235. int originatingClient = clientNumber;
  236.  
  237. for (int loop = 0; loop < MAX_CLIENTS; loop++)
  238. {
  239. // Send a message to the client saying "OK" to indicate the incoming connection has been accepted
  240. //strcpy( buffer, SERVER_NOT_FULL.c_str() );
  241. int msgLength = strlen(buffer) + 1;
  242.  
  243. // If the message length is more than 1 (i.e. client pressed enter without entering any other text), then
  244. // send the message to all connected clients except the client who originated the message in the first place
  245. if (msgLength > 1 && loop != originatingClient && isSocketFree[loop] == false)
  246. {
  247. file << "Retransmitting message: " << buffer << " (" << msgLength << " bytes) to client number: " << loop << std::endl;
  248. SDLNet_TCP_Send(clientSocket[loop], (void *)buffer, msgLength);
  249. }
  250.  
  251. }
  252.  
  253. // If the client told us to shut down the server, then set the flag to get us out of the main loop and shut down
  254. if (strcmp(buffer, "shutdown") == 0)
  255. {
  256. serverRunning = false;
  257. file << "Disconnecting all clients and shutting down the server..." << std::endl << std::endl;
  258. }
  259. }
  260. } // End of if client socket is active check
  261. myString.str("");//most awesome way to clear a stringstream
  262. myString << clientCount;//int to stringstream
  263. clientcount_string = myString.str();//stringstream to string
  264. } // End of server socket check sockets loop
  265.  
  266. // Check for events (Currently keyboard)
  267. al_wait_for_event(event_queue, &ev);
  268.  
  269. std::string userInput = "";
  270. int status;
  271.  
  272. if (ev.type == ALLEGRO_EVENT_TIMER) {
  273. redraw = true;
  274. }
  275. if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
  276. serverRunning = false; // If we must quit, then do so
  277. }
  278. else if (ev.type == ALLEGRO_EVENT_KEY_DOWN)
  279. {
  280. if (ev.keyboard.keycode == ALLEGRO_KEY_ENTER)
  281. {
  282. if (userInput.length() > 0) { }
  283. }//send the message
  284. }
  285.  
  286. if (ev.type == ALLEGRO_EVENT_KEY_CHAR) { //Add to the message
  287. status = ev.keyboard.unichar; // Get the keypress
  288.  
  289. file << "the key pressed was " << status << " " << (char)status << std::endl;
  290.  
  291. if (status == 8) {
  292. if (userInput.length() > 0) {
  293. userInput.erase(userInput.length() - 1);
  294. }
  295. }
  296. else if (status >= 65 && status <= 122) {
  297. userInput += (char)status;
  298. }
  299. }
  300. else {
  301. status = -1;
  302. }
  303.  
  304. if (redraw && al_is_event_queue_empty(event_queue)) {
  305. al_clear_to_color(al_map_rgb(0, 0, 0));
  306.  
  307. al_draw_text(font, al_map_rgb(255, 255, 255), 20, 20, 0, text.c_str());
  308. al_draw_text(font, al_map_rgb(255, 255, 255), 20, 40, 0, text2.c_str());
  309. al_draw_text(font, al_map_rgb(255, 255, 255), 20, 100, 0, userInput.c_str());
  310. al_draw_text(font, al_map_rgb(255, 255, 255), 20, 100, 0, "Hello");
  311.  
  312. al_flip_display();
  313. }
  314.  
  315. } while (serverRunning);
  316.  
  317. file << "Server shutting down" << std::endl;
  318. // Free our socket set (i.e. all the clients in our socket set)
  319. SDLNet_FreeSocketSet(socketSet);
  320.  
  321. // Close our server socket, cleanup SDL_net and finish!
  322. SDLNet_TCP_Close(serverSocket);
  323.  
  324. SDLNet_Quit();
  325.  
  326. al_destroy_font(font);
  327. al_destroy_timer(timer);
  328. al_destroy_event_queue(event_queue);
  329. al_destroy_display(display);
  330.  
  331. return 0;
  332. }
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.cpp:5:30: fatal error: allegro5/allegro.h: No such file or directory
compilation terminated.
stdout
Standard output is empty