TalkServerThread.java Source code

Java tutorial

Introduction

Here is the source code for TalkServerThread.java

Source

    /* From http://java.sun.com/docs/books/tutorial/index.html */

    /*
     * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     * -Redistribution of source code must retain the above copyright notice, this
     *  list of conditions and the following disclaimer.
     *
     * -Redistribution in binary form must reproduce the above copyright notice,
     *  this list of conditions and the following disclaimer in the documentation
     *  and/or other materials provided with the distribution.
     *
     * Neither the name of Sun Microsystems, Inc. or the names of contributors may
     * be used to endorse or promote products derived from this software without
     * specific prior written permission.
     *
     * This software is provided "AS IS," without a warranty of any kind. ALL
     * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
     * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
     * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
     * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
     * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
     * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
     * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
     * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
     * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
     * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
     *
     * You acknowledge that this software is not designed, licensed or intended
     * for use in the design, construction, operation or maintenance of any
     * nuclear facility.
     */

    /*
     * 1.1 version.
     */

    import java.io.*;
    import java.net.*;
    import java.util.*;

class TalkServerThread extends Thread {
    public Socket socket;
    public BufferedReader is;
    public BufferedWriter os;
    TalkServer server;
    boolean DEBUG = false;

    public String toString() {
        return "TalkServerThread: socket = " + socket
               + "; is = " + is
               + "; os = " + os;
    }

    TalkServerThread(Socket socket, TalkServer server) throws IOException {
        super("TalkServer");

        is = new BufferedReader(
       new InputStreamReader(socket.getInputStream()));
        os = new BufferedWriter(
       new OutputStreamWriter(socket.getOutputStream()));

        if (is == null) {
            System.err.println("TalkServerThread: Input stream seemed "
                               + "to be created successfully, but it's null.");
            throw new IOException();
        }

        if (os == null) {
            System.err.println("TalkServerThread: Output stream seemed "
                               + "to be created successfully, but it's null.");
            throw new IOException();
        }

        this.socket = socket;
        this.server = server;
    }

    public void run() {
        while (socket != null) {
            try {
                //Read data.
                String str = is.readLine();

                //Pass it on.
                if (str != null) {
                    server.forwardString(str, this);
                }
            } catch (EOFException e) { //No more data on this socket...
                server.forwardString("SERVER SAYS other applet disconnected",
                                     this);
                cleanup();
                return;
            } catch (NullPointerException e) { //Socket doesn't exist...
                server.forwardString("SERVER SAYS no socket to other applet",
                                     this);
                cleanup();
                return;
            } catch (IOException e) { //Read problem..
                server.forwardString("SERVER SAYS socket trouble with other applet",
                                     this);
                cleanup();
                return;
            } catch (Exception e) { //Unknown exception. Complain and quit.
                System.err.println("Exception on is.readLine():");
                e.printStackTrace();
                cleanup();
                return;
            }
        }
    }

    protected void finalize() {
        cleanup();
    }

    void cleanup() {
        try {
            if (is != null) {
                is.close();
                is = null;
            }
        } catch (Exception e) {} //Ignore errors.

        try {
            if (os != null) {
                os.close();
                os = null;
            }
        } catch (Exception e) {} //Ignore errors.

        try {
            if (socket != null) {
                socket.close();
                socket = null;
            }
        } catch (Exception e) {} //Ignore errors.
    }

}

    /*
     * 1.1 version.
     */

    import java.net.*;
    import java.io.*;

class TalkServer {
    TalkServerThread[] tstList = new TalkServerThread[2];
    boolean DEBUG = false;

    public static void main(String[] args) {
        new TalkServer().start();
    }

    public void start() {
        ServerSocket serverRSocket = null;
        int numConnected = 0;

        try {
            serverRSocket = new ServerSocket(0);
            System.out.println("TalkServer listening on rendezvous port: "
                               + serverRSocket.getLocalPort());
        } catch (IOException e) {
            System.err.println("Server could not create server socket for rendezvous.");
            return;
        }

        while (true) {

            //Connect to two clients.
            while (numConnected < 2) {
                TalkServerThread tst;
                tst = connectToClient(serverRSocket);
                if (tst != null) {
                    numConnected++;
                    if (tstList[0] == null) {
                        tstList[0] = tst;
                    } else {
                        tstList[1] = tst;
                    }
                }
            } //end while (numConnected < 2) loop

            if (DEBUG) {
                try {
                    System.out.println("tst #0 = " + tstList[0]);
                } catch (Exception e) {}
                try {
                    System.out.println("tst #1 = " + tstList[1]);
                } catch (Exception e) {}
            }

            //If they're really OK, tell them to start writing.
            if (everythingIsOK(0) & everythingIsOK(1)) {
                for (int i = 0; i < 2; i++) {
                    writeToStream("START WRITING!\n----------------------"
                                  + "-------------", tstList[i].os);
                }
            } else {
                System.err.println("2 server threads created, but "
                                   + "not everything is OK");
            }

            while (numConnected == 2) {
                if (!everythingIsOK(0)) {
                    if (DEBUG) {
                        System.out.println("Applet #0 is hosed; disconnecting.");
                    }
                    numConnected--;
                    cleanup(tstList[0]);
                    tstList[0] = null;
                }
                if (!everythingIsOK(1)) {
                    if (DEBUG) {
                        System.out.println("Applet #1 is hosed; disconnecting.");
                    }
                    numConnected--;
                    cleanup(tstList[1]);
                    tstList[1] = null;
                }
                       try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                } 
            } //end while(numConnected==2) loop

            if (DEBUG) {
                try {
                    System.out.println("Number of connections = " + numConnected);
                    System.out.println("tst #0 = " + tstList[0]);
                    System.out.println("tst #1 = " + tstList[1]);
                } catch (Exception e) {}
            }

        } //end while (true) loop
    }

    protected TalkServerThread connectToClient(ServerSocket serverRSocket) {
        Socket rendezvousSocket = null;
        TalkServerThread tst = null;

        //Listen for client connection on the rendezvous socket.
        try {
            rendezvousSocket = serverRSocket.accept();
        } catch (IOException e) {
            System.err.println("Accept failed.");
            e.printStackTrace();
            return null;
        }

        //Create a thread to handle this connection.
        try {
            tst = new TalkServerThread(rendezvousSocket, this);
            tst.start();
        } catch (Exception e) {
             System.err.println("Couldn't create TalkServerThread:");
            e.printStackTrace();
            return null;
        }

        writeToStream("Successful connection. "
                      + "Please wait for second applet to connect...",
                      tst.os);
        return tst;
    }

    boolean everythingIsOK(int tstNum) {
        TalkServerThread tst = tstList[tstNum];

        if (tst == null) {
            if (DEBUG) {
                System.out.println("TalkServerThread #" + tstNum
                                   + " is null");
            }
            return false;
        } else {
            if (tst.os == null) {
                if (DEBUG) {
                    System.out.println("TalkServerThread #" + tstNum
                                       + " output stream is null.");
                }
                return false;
            }
            if (tst.is == null) {
                if (DEBUG) {
                    System.out.println("TalkServerThread #" + tstNum
                                       + " input stream is null.");
                }
                return false;
            }
            if (tst.socket == null) {
                if (DEBUG) {
                    System.out.println("TalkServerThread #" + tstNum
                                       + " socket is null.");
                }
                return false;
            }
        }
        return true;
    }

    void cleanup(TalkServerThread tst) {
        if (tst != null) {
            try {
                if (tst.os != null) {
                    tst.os.close();
                    tst.os = null;
                }
            } catch (Exception e) {} //Ignore errors
            try {
                if (tst.is != null) {
                    tst.is.close();
                    tst.is = null;
                }
            } catch (Exception e) {} //Ignore errors
            try {
                if (tst.socket != null) {
                    tst.socket.close();
                    tst.socket = null;
                }
            } catch (Exception e) {} //Ignore errors
        }
    }

    public void forwardString(String string, TalkServerThread requestor) {
        BufferedWriter clientStream = null;

        if (tstList[0] == requestor) {
            if (tstList[1] != null) {
                clientStream = tstList[1].os;
            } else {
                if (DEBUG) {
                    System.out.println("Applet #0 has a string to forward, "
                                       + "but Applet #1 is gone...");
                }
                return;
            }
        } else {
            if (tstList[0] != null) {
                clientStream = tstList[0].os;
            } else {
                if (DEBUG) {
                    System.out.println("Applet #1 has a string to forward, "
                                       + "but Applet #0 is gone...");
                }
                return;
            }
        }

        if (clientStream != null) {
            writeToStream(string, clientStream);   
        } else if (DEBUG) {
            System.out.println("Can't forward string -- no output stream.");
        }
    }

    public void writeToStream(String string, BufferedWriter stream) {
        if (DEBUG) {
            System.out.println("TalkServer about to forward data: "
                               + string);
        }

        try { 
            stream.write(string);
       stream.newLine();
            stream.flush();
            if (DEBUG) {
                System.out.println("TalkServer forwarded string.");
            }
        } catch (IOException e) {
            System.err.println("TalkServer failed to forward string:");
            e.printStackTrace();
            return;
        } catch (NullPointerException e) {
            System.err.println("TalkServer can't forward string "
                               + "since output stream is null.");
            return;
        }
    }

}

    /*
     * 1.1 version.
     */

    import java.applet.Applet;
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.net.*;
    import java.util.*;

    public class TalkClientApplet extends Applet implements Runnable, ActionListener {
        Socket socket;
        BufferedWriter os;
        BufferedReader is;
        TextField portField, message;
        TextArea display;
        Button button;
        int dataPort;
        boolean trysted;
        Thread receiveThread;
        String host;
        boolean DEBUG = false;
        String newline;

        public void init() {
            //Get the address of the host we came from.
            host = getCodeBase().getHost();

            //Set up the UI.
            GridBagLayout gridBag = new GridBagLayout();
            GridBagConstraints c = new GridBagConstraints();
            setLayout(gridBag);

            message = new TextField("");
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridwidth = GridBagConstraints.REMAINDER;
            gridBag.setConstraints(message, c);
            message.addActionListener(this);
            add(message);

            display = new TextArea(10, 40);
            display.setEditable(false);
            c.weightx = 1.0;
            c.weighty = 1.0;
            c.fill = GridBagConstraints.BOTH;
            gridBag.setConstraints(display, c);
            add(display);

            Label l = new Label("Enter the port (on host " + host + ") to send the request to:", Label.RIGHT);
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridwidth = 1;
            c.weightx = 0.0;
            c.weighty = 0.0;
            gridBag.setConstraints(l, c);
            add(l);

            portField = new TextField(6);
            c.fill = GridBagConstraints.NONE;
            gridBag.setConstraints(portField, c);
            portField.addActionListener(this);
            add(portField);

            button = new Button("Connect");
            gridBag.setConstraints(button, c);
            button.addActionListener(this);
            add(button);

            newline = System.getProperty("line.separator");
        }

        public synchronized void start() {
            if (DEBUG) {
                System.out.println("In start() method.");
            }
            if (receiveThread == null) {
                trysted = false;
                portField.setEditable(true);
                button.setEnabled(true);
                os = null;
                is = null;
                socket = null;
                receiveThread = new Thread(this);
                receiveThread.start();
                if (DEBUG) {
                    System.out.println("  Just set everything to null and started thread.");
                }
            } else if (DEBUG) {
                System.out.println("  receiveThread not null! Did nothing!");
            }
        }

        public synchronized void stop() {
            if (DEBUG) {
                System.out.println("In stop() method.");
            }
            receiveThread = null;
            trysted = false;
            portField.setEditable(true);
            button.setEnabled(true);
            notify();

            try { //Close input stream.
                if (is != null) {
                    is.close();
                    is = null;
                }
            } catch (Exception e) {
            } //Ignore exceptions.

            try { //Close output stream.
                if (os != null) {
                    os.close();
                    os = null;
                }
            } catch (Exception e) {
            } //Ignore exceptions.

            try { //Close socket.
                if (socket != null) {
                    socket.close();
                    socket = null;
                }
            } catch (Exception e) {
            } //Ignore exceptions.
        }

        public Insets getInsets() {
            return new Insets(4, 4, 5, 5);
        }

        public void paint(Graphics g) {
            Dimension d = getSize();
            Color bg = getBackground();

            g.setColor(bg);
            g.draw3DRect(0, 0, d.width - 1, d.height - 1, true);
            g.draw3DRect(3, 3, d.width - 7, d.height - 7, false);
        }

        public synchronized void actionPerformed(ActionEvent event) {
            int port;

            if (DEBUG) {
                System.out.println("In action() method.");
            }

            if (receiveThread == null) {
                start();
            }

            if (!trysted) {
                //We need to attempt a rendezvous.

                if (DEBUG) {
                    System.out.println("  trysted = false. " + "About to attempt a rendezvous.");
                }

                //Get the port the user entered...
                try {
                    port = Integer.parseInt(portField.getText());
                } catch (NumberFormatException e) {
                    //No integer entered. 
                    display.append("Please enter an integer below." + newline);
                    return;
                }
                //...and rendezvous with it.
                rendezvous(port);

            } else { //We've already rendezvoused. Just send data over.
                if (DEBUG) {
                    System.out.println("  trysted = true. " + "About to send data.");
                }
                String str = message.getText();
                message.selectAll();

                try {
                    os.write(str);
                    os.newLine();
                    os.flush();
                } catch (IOException e) {
                    display.append("ERROR: Applet couldn't write to socket." + newline);
                    display.append("...Disconnecting." + newline);
                    stop();
                    return;
                } catch (NullPointerException e) {
                    display.append("ERROR: No output stream!" + newline);
                    display.append("...Disconnecting." + newline);
                    stop();
                    return;
                }
                display.append("Sent: " + str + newline);
            }
        }

        synchronized void waitForTryst() {
            //Wait for notify() call from action().
            try {
                wait();
            } catch (InterruptedException e) {
            }

            if (DEBUG) {
                System.out.println("waitForTryst about to return. " + "trysted = " + trysted + ".");
            }

            return;
        }

        public void run() {
            String received = null;

            waitForTryst();

            //OK, now we can send messages.
            while (Thread.currentThread() == receiveThread) {
                try {
                    //Wait for data from the server.
                    received = is.readLine();

                    //Display it.
                    if (received != null) {
                        display.append("Received: " + received + newline);
                    } else { //success but no data...
                        System.err.println("End of stream?");
                        return; //XXX
                    }
                } catch (IOException e) { //Perhaps a temporary problem?
                    display.append("NOTE: Couldn't read from socket.\n");
                    return;
                }
            }
        }

        private void rendezvous(int port) {
            //Try to open a socket to the port.
            try {
                socket = new Socket(host, port);
            } catch (UnknownHostException e) {
                display.append("ERROR: Can't find host: " + host + newline);
                return;
            } catch (IOException e) {
                display.append(
                        "ERROR: Can't open socket on rendezvous port " + port + " (on host " + host + ")." + newline);
                return;
            }

            //Try to open streams to read and write from the socket.
            try {
                os = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            } catch (IOException e) {
                display.append("ERROR: Created data socket but can't " + "open stream on it." + newline);
                display.append("...Disconnecting." + newline);
                stop();
                return;
            }

            if ((os != null) & (is != null)) {
                if (DEBUG) {
                    System.out.println("Successful rendezvous.");
                    System.out.println("socket = " + socket);
                    System.out.println("output stream = " + os);
                    System.out.println("input stream = " + is);
                }
                //Let the main applet thread know we've successfully rendezvoused.
                portField.setEditable(false);
                button.setEnabled(false);
                trysted = true;
                notify();
            } else {
                display.append("ERROR: Port is valid but communication failed. " + "Please TRY AGAIN." + newline);
            }
        }

    }