/* Class : gameserver * Author : Andrew Miller * Version : 7/1/96 JAVA SDK 1.02 * Notice : Copyright (C) 1996 Andrew Miller * * The central idea when designing this server was to make it as stupid as possible and yet * it must still be able to perform simple network duties. The reason for this is that * allowing the client have control and making it capable of determining game play makes * the server more flexible. You can be playing multiple games with multiple amounts of * people. The server just doesnt care. * * It is responsible for: * 1:looking for connections * 2:adding those connections to its global list (along with a unique ID number) * 3:broadcasting to all the connections the current list of users (and their unique IDs) * 4:support for name changing * 5:letting the other users know when a client has disconnected (so they can update their * own user lists). * 6:looking for "directives" and distributing them to the correct clients. * * Any message received by the server is parsed to determine whether or not it is a special * instruction. Directives are the most useful function that the server provides. The * server doesnt care what is contained in the server (usually game information), but it * looks to the end of the directive for a list of clients to redistribute the directive to. * This allows for specific interaction among a selected group of clients. * * * Code and ideas for these classes comes in part from the following sources: * * - 'Java in a Nutshell' by David Flanagan * - 'Java Unleashed' by Sams Net * - 'Writing Java Applets' by John Rodley * - 'Simple Server' by Kyle Palmer * - 'Multiserver' by Jeff Breidenbach * */ import java.net.*; import java.io.*; import java.lang.*; //declaration of class gameserver class gameserver { static int users = 0; //the number of active users static int unique_id = 1; //setup unique id number for users static int DEFAULT_PORT = 8999; static networksocket clients[] = new networksocket[29]; public static void main(String args[]) { ServerSocket serverSocket = null; int i, port = 0, connectTest; boolean chatFlag = true; if (args.length == 1) { try { port = Integer.parseInt (args[0]);} catch (NumberFormatException e) { port = 0;} } if (port == 0) port = DEFAULT_PORT; try { serverSocket = new ServerSocket(port); } catch (IOException e) { System.out.println("Could not listen on port: " + e); System.exit(1); } Socket clientSocket = null; connection user = new connection(serverSocket); if (users == 0) { //if no users, wait for one try { clientSocket = serverSocket.accept(); } catch (IOException e) { System.out.println("Accept failed: " + e); System.exit(1); } add_client(new networksocket(clientSocket)); //add the client } String inputStream; //string for Input IO String outputStream; //string for Output IO //get the vector the write to user.start(); //start polling for new users try { inputStream = "Connected! Double-click user to challenge"; i = users; while (users >= 0) { if (users>0 && i<=users ){ connectTest = clients[i].is_readable(); if (connectTest == -1){ //if connection stale remove_client(i); //remove the client } else if (connectTest == 1){ //if there is a line to get inputStream = clients[i].read_stream(); //get the string chatFlag = process_line(inputStream,i); //process the line if (chatFlag){ //echo line if is plain text if (clients[i] != null) System.out.println(clients[i].name+": "+inputStream); write_all((clients[i].name).toUpperCase()+": "+inputStream); //echo it } } } try{ user.join(2); //give connection testing some time } catch(InterruptedException e) {} if (user.connected() == true){ add_client(new networksocket(user.get_socket())); user.resume(); } i++; if (i>users && users>=1) i=1; if (i>users && users<1) i=0; } serverSocket.close(); }catch(IOException e){} } // sends all the names and IDs in the servers list to all the clients static void send_names(){ String names = new String("!!names!!"); //start with indicator int i; if (users < 1) return; // do nothing for a no users for (i=1;i<=users;i++) //add all users if (clients[i] != null) //if everthing is in order names = names + Integer.toString(clients[i].id) +"~" + clients[i].name + "|"; //append names and delimiters write_all(names); //echo the names to everyone } // process the incoming data stream and return a status flag static boolean process_line (String line,int i){ int next, usernum; String temp ; String directive = new String("!!directive!!"); //new indicator //false if don't echo line if (line.startsWith("!!directive!!")) { //instruction to send directive to users line = line.substring(13); next = line.indexOf('|'); // get position of next delimeters directive = directive + line.substring(0, next)+","+clients[i].name; line = line.substring(next+1); while (line.length() > 0) { // send directive to players in list next = line.indexOf('|'); if (next == -1) break; // end of list temp = line.substring(0, next); // check for range if ((Integer.parseInt(temp)) > users) break; clients[Integer.parseInt(temp)].write_stream(directive); line = line.substring(next+1); } return false; } else if (line.startsWith("!!name!!")){ //instruction to change name clients[i].name = line.substring(8); //name is the rest of line clients[i].write_stream("Name changed to "+line.substring(8)); System.out.println (line.substring(8)+" enters"); send_names(); //send an updated names list return false; //don't echo this string } else if (line.equals("!!quit!!")){ //instruction to quit write_all(clients[i].name+" is logging out."); //tell everyone System.out.println(clients[i].name+" logged out"); remove_client(i); return false; } return true; } // writes the string to all the users contained in the server's list static void write_all (String text) { //write to all the clients int i; for (i=1;i<=users;i++) clients[i].write_stream(text); } // adds a client and assigns it a unique id, then updates client name lists static void add_client(networksocket client) { synchronized(clients) { if (users >= 25){ client.write_stream("Sorry, there already 25 users."); client.kill(); //don't allow too many return; } clients[++users] = client; //add the client to the list clients[users].id = unique_id++; clients[users].write_stream("!!directive!!mssge,uid,"+Integer.toString(clients[users].id)); clients[users].write_stream("Connected! Double-click user to challenge"); send_names(); //update everyones names list } } // removes a client from the list and updates the client name lists static void remove_client(int client){ synchronized(clients) { clients[client].kill(); //close everything clients[client]=clients[users]; clients[users]=null; users--; if (users <= 0) unique_id = 1; send_names(); //update the names list } } }