package talk; import java.util.Vector; import java.util.Enumeration; import java.net.*; import java.io.*; class Connection implements Runnable { // The socket through which we talk to the client. Socket socket; // The input stream on which we will read messages. // DataInputStream is a very useful class because it // has standard methods to read integers, strings, // and so forth. DataInputStream inputStream; // The output stream on which we will write messages. DataOutputStream outputStream; // The thread that will read messages from the client. Thread inputThread; // The thread that will write messages to the client. Thread outputThread; // A queue of strings to be sent to the client. Vector outputStrings; // The server. Server owner; // The name of the user. String name; Connection(Server ownerArg, Socket s) { owner = ownerArg; socket = s; outputStrings = new Vector(); // Start input and output threads. inputThread = new Thread(this); outputThread = new Thread(this); inputThread.start(); outputThread.start(); } public void run() { if (Thread.currentThread() == inputThread) { // Read input from the server. inputRun(); } else if (Thread.currentThread() == outputThread) { // Write output to the server. outputRun(); } } void inputRun() { try { // Set up the input stream. inputStream = new DataInputStream( socket.getInputStream()); // Get the user's name. name = inputStream.readUTF(); // Announce the user. owner.outputLine(this, "* * * " + name + " has connected."); while (true) { // Input a line from the client. String s = inputStream.readUTF(); // Output it to the other connections. owner.outputLine(this, "<" + name + "> " + s); } } catch (java.io.IOException e) { // Something went wrong. Stop this connection. outputThread.stop(); owner.forgetConnection(this); } } void outputRun() { try { // Set up the output stream. outputStream = new DataOutputStream( socket.getOutputStream()); while (true) { outputStep(); } } catch (java.io.IOException e) { // Something went wrong. Stop this connection. inputThread.stop(); owner.forgetConnection(this); } } void outputStep() throws java.io.IOException { // Do any work pending // in the output queue. flushOutputStrings(); // Synchronize on the output queue, // then, if no output is ready yet, // signal our willingness to wait // until it is. synchronized (outputStrings) { if (outputStrings.size() == 0) { try { outputStrings.wait(); } catch (InterruptedException ie) { // This shouldn't happen. } } } } // Send the current contents of the output queue. void flushOutputStrings() throws java.io.IOException { while (outputStrings.size() > 0) { // Output a string to the server String s = (String) outputStrings.elementAt(0); outputStream.writeUTF(s); // And remove what we have sent // from our queue of strings outputStrings.removeElementAt(0); } } // Accept a line of input from the server, // to be output to the client. void inputLine(String s) { // We don't want to output it now; that could // cause the server to pause. Instead, we add // it to the queue of strings to be sent by // the output thread, and we notify the // output thread that the queue has changed. synchronized (outputStrings) { outputStrings.addElement(s); // Notify the output thread that there // is new data in the queue. outputStrings.notify(); } } }