//******************************************************************** // server.java //******************************************************************** // // A Prototype Remote Data Monitoring System // with FallingObject Simulation Data // // DataServer provides data to DataClients. A DataClient sends // a request for data from the Server. DataServer responds by first // sending an integer for the number of data points and then sends // the floating point values. // // DataServer runs standalone. The server is meant to be run at // the same time that a separate data acquisition program is running. // The DAQ program would be programmed to periodically update a file // with the data of interest. This server would then read this file // and send the data to the DataClients. // // An instance of the thread class DataSender is assigned to each // DataClient socket. It monitors the socket for requests from the // DataClient and then reads the data and sends it to the DataClient. // The DataSender consists primarily of a run() that uses functions // and properties of the DataServer. // // This version of DataServer also holds an instance of the // FallingObject applet (Lecture 11B) in a frame. From the G_Detector // instance that measures the rate of free fall, simulated data // is created and saved in a histgram. This histogram data is passed // to the DataClient when it requests it. // //******************************************************************** package DataMonitor; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import FOExperiment.*; //******************************************************************** public class DataServer extends Frame implements ActionListener{ ServerSocket server_socket; String user[]; BufferedReader net_input[]; OutputStream net_output[]; int DataServerPort = 1111;// Default port number DataSender senders[]; static int client_counter = 0; static int maxUsers = 10; static int NumDataVals=10; static FallingObject FOApplet = null; static DataServer dataServeAppletHolder = null; //---------------------------------------------------------------- public static void main(String args[]){ dataServeAppletHolder = new DataServer(); FOApplet = new FallingObject(); dataServeAppletHolder.add("Center", FOApplet); FOApplet.init(); FOApplet.start(); // Use an adapter to close the window WindowListener listener = new WindowAdapter() { public void windowClosing(WindowEvent e){ FOApplet.stop(); dataServeAppletHolder.dispose(); System.exit(0); } }; dataServeAppletHolder.addWindowListener(listener); dataServeAppletHolder.setSize(525,550); dataServeAppletHolder.pack(); dataServeAppletHolder.show(); dataServeAppletHolder.startServing(); } //---------------------------------------------------------------- public DataServer(){ // Set up frame setTitle("DataServer & FallingObject Applet"); Menu m = new Menu("File"); MenuItem mi = new MenuItem( "Quit" ); mi.addActionListener( this ); m.add(mi); MenuBar mb = new MenuBar(); mb.add(m); setMenuBar(mb); } //---------------------------------------------------------------- public void startServing(){ // Now setup server stuff user = new String[maxUsers]; net_input = new BufferedReader[maxUsers]; net_output = new OutputStream[maxUsers]; senders = new DataSender[maxUsers]; // The server_socket is used to make connections to // DataClients at this port number try{ server_socket = new ServerSocket(DataServerPort); }catch (IOException e) { System.out.println("Error in server socket"); return; } System.out.println("Waiting for users..."); // Loop here to grab clients while (true){ try { // accept() only returns when a connection has // been made. Socket socket = server_socket.accept(); // Do the setup this socket and then loop // back around to wait for the next DataClient. service_request(socket); } catch (IOException e){ System.out.println("Exception: <" + e + ">"); break; } } } //---------------------------------------------------------------- public void actionPerformed( ActionEvent e ) { if ( e.getActionCommand().equals("Quit") ){ FOApplet.stop(); dispose(); System.exit(0); } } //---------------------------------------------------------------- // Set up the connection to the DataClient. This means getting the // IO streams, carrying out the login prototcol, and then starting // a DataSender thread to monitor the DataClient. // // The code is a bit messy because we check both reads and writes // for errors in case the connection breaks down. // // The reads catch their own IOExceptions and return a null, while // string writes use a PrintStream that doesn't throw IOException. So // we use the checkError() method and throw it ourselves. // public void service_request(Socket socket) { InputStream input; OutputStream output; try{ input = socket.getInputStream(); output = socket.getOutputStream(); } catch (IOException e){ System.out.println("Unable to get input/output streams"); return; } if (client_counter >= maxUsers ) { try{ write_net_output_line( new PrintStream(output), "Sorry, We've reached maximum of " + maxUsers + " clients"); return; } catch (IOException e){ System.out.println("Connection fails during login"); return; } } // Keep an array of input streams for each client. Use // DataInputStream wrapper so we can use the readLine() methods. net_input[client_counter] = new BufferedReader(new InputStreamReader(input)); net_output[client_counter] = output; // Do a simple login protocol. Note a password check could // be added here. try{ write_net_output_line(net_output[client_counter], "Username: "); } catch (IOException e){ System.out.println("Connection fails during login"); return; } user[client_counter] = read_net_input_line(net_input[client_counter]); if( user[client_counter] == null ) { System.out.println("Connection fails during login"); return; } try{ write_net_output_line(net_output[client_counter], "Login successful"); } catch (IOException e){ System.out.println("Connection fails during login"); return; } System.out.println(user[client_counter] + " Connected! "); System.out.println(socket.toString()); // The login is successful so now spin off the DataSender to // service this client. senders[client_counter] = new DataSender(this, client_counter); senders[client_counter].start(); System.out.println("DataReader " + client_counter +" started"); client_counter++; } //---------------------------------------------------------------- // Whenever one client disconnects we need to reset the array to // remove the empty slot. public void clientLogoff(int id) { net_input[id] = null; net_output[id] = null; senders[id] = null; for( int i=id; i<(client_counter-1); i++){ net_input[i] = net_input[i+1]; net_output[i] = net_output[i+1]; senders[i] = senders[i+1]; senders[i].index = i; user[i] = user[i+1]; } --client_counter; } //---------------------------------------------------------------- String read_net_input_line(BufferedReader input) { try{ return input.readLine(); }catch (IOException e){ return null; } } //---------------------------------------------------------------- // Output is wrapped with a PrintWriter, which doesn't throw // IOException. So we use the checkError() method and throw it // ourselves. void write_net_output_line(OutputStream output, String string) throws IOException { PrintWriter pout = new PrintWriter( new OutputStreamWriter(output, "8859_1"), true ); pout.println(string); if( pout.checkError()) throw (new IOException()); pout.flush(); if( pout.checkError()) throw (new IOException()); } //---------------------------------------------------------------- void write_net_output_int(DataOutputStream output, int i) throws IOException { output.writeInt(i); output.flush(); } //---------------------------------------------------------------- void write_net_output_float(DataOutputStream output,float f) throws IOException { output.writeFloat(f); output.flush(); } }