Java TCP Sockets and Swing Tutorial by fso56144

VIEWS: 195 PAGES: 11

									  Java TCP Sockets and Swing Tutorial
                                   by Ashish Myles
                              modified by Gustavo Alatta




Introduction

This tutorial is aimed for programmers with at least a little experience with Java.
For introductory material on Java, check out Sun's Java Tutorial and Java
Documentation, which can be accessed from Sun's Java home page. Information
on how to compile and run programs is also available there. This page takes you
step-by-step through compiling and running your first Java program. For the
following tutorial, make sure to download and install JDK1.4 or JDK1.5 - also
known as Java 2. The latest Java Development Kit can be downloaded here. The
following tutorial introduces Java sockets and Swing separately before combining
them into a TCP chat program.




TCP Socket Programming

Introduction

Let's cover Java TCP sockets first since they are much simpler than Swing. The
beauty of Java sockets is that no knowledge whatsoever of the details of TCP is
required. TCP stands for Transmission Control Protocol and is a standard
protocol data transmission with confirmation of data reception. That's as far as I
know on the subject, and yet I managed to make a chat program.
Concept

In order to initiate a TCP session, a server and a client are required. Firstly, a
server is set up to listen at a given port. The server waits and does nothing until a
client attempts to connect that port. If everything goes fine, the connection is
successful and both the server and client have an instance of the Socket class.
From each instance of this class, an input stream and an output stream can be
obtained, and all communication is done via these streams.


Example

The Socket class is in the java.net package, so be sure to say import java.net.*; at the
beginning of your file. The following is a simple example that illustrates the
different portions of a server/client pair. This example works using localhost, which
corresponds to the default local computer IP address of 127.0.0.1. This way, both
the server and the client will be running on the same computer. Server.java and
Client.java   contain the server and client source code for this simple example.
Here is the server code (Server.java):

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


class Server {
  public static void main(String args[]) {
    String data = "Toobie ornaught toobie";
    try {
      ServerSocket srvr = new ServerSocket(1234);
      Socket skt = srvr.accept();
      System.out.print("Server has connected!\n");
      PrintWriter out = new PrintWriter(skt.getOutputStream(), true);
      System.out.print("Sending string: '" + data + "'\n");
      out.print(data);
      out.close();
      skt.close();
            srvr.close();
        }
        catch(Exception e) {
            System.out.print("Whoops! It didn't work!\n");
        }
    }
}


The key portions of this program are in the try{} block. The ServerSocket
instantiation is what sets up the server to listen at the given port. The server is
automatically set up at the computer on which it is run. The Socket instantiation on
the next line uses the accept() method of ServerSocket. This method waits until a
client attempts to connect to the server, and it returns an instance of the Socket
class. This Socket instance (skt) is now the "warp tunnel" through which we can
communicate with the client. skt.getOutputStream() returns the output stream
through which the server can talk to the client, and skt.getInputStream() returns the
input stream through with the server can hear the client. This example creates a
PrintWriter       instance using the output stream for easier output and sends the data
(stored in data) to the client (out.print(data);). Bingo! Easy as that! After everything is
done, all the streams and sockets should be closed before the program is exited.
Now, let's see the client code.
Here is the client code (Client.java):

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


class Client {
    public static void main(String args[]) {
        try {
            Socket skt = new Socket("localhost", 1234);
            BufferedReader in = new BufferedReader(new
              InputStreamReader(skt.getInputStream()));
            System.out.print("Received string: '");
            while (!in.ready()) {}
            System.out.println(in.readLine()); // Read one line and output it


            System.out.print("'\n");
            in.close();
        }
        catch(Exception e) {
            System.out.print("Whoops! It didn't work!\n");
        }
    }
}


Once again, the meat of the program is in the try{} block. A connection to the
server is attempted through the instantiation of the Socket class. It attempts to
contact the server at localhost through port 1234 - the same port where the server
is listening. Once the socket is at hand, it works exactly the same as the one
obtained through the ServerSocket class in Server.java. This time, the input stream is
obtained and a BufferedReader is instantiated using it. The data is read from this
stream and displayed to the screen. Simple yet again!



Java/Swing Programming

Introduction

Swing is a rapid GUI development tool that is part of the standard Java
development kit. It was primarily developed due to the shortcomings of the
Abstract Windows Toolkit (AWT). For example, Swing's JButton class enhances
the AWT Button class to allow not only text, but images on the button. In addition,
all Swing components support assistive technologies.


Swing Components
I am only going to go over a few basic Swing components:

           JFrame
           JPanel
           JButton

If you know how to use these basic components, using the others is simple. Usually, while
making a GUI-based application, you instantiate a JFrame and choose its layout. Then you put
one or more JPanels in the JFrame if you want to. JPanels also have different layout options like
JFrames do. After that, you add other components. The following is the code corresponding to
what I just said. It can also be found in SimpleGui1.java.
import java.lang.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


class SimpleGui1 {
    public static void main(String args[]) {
        // Let's make a button first
        JButton btn = new JButton("Click Me!");
        btn.setMnemonic(KeyEvent.VK_C); // Now you can hit the button with Alt-C


        // Let's make the panel with a flow layout.
        // Flow layout allows the components to be
        // their preferred size.
        JPanel pane = new JPanel(new FlowLayout());
        pane.add(btn); // Add the button to the pane


        // Now for the frame
        JFrame fr = new JFrame();
        fr.setContentPane(pane); // Use our pane as the default pane
        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exit program when frame is closed
        fr.setLocation(200, 200); // located at (200, 200)
        fr.pack();             // Frame is ready. Pack it up for display.
        fr.setVisible(true);       // Make it visible
    }
}
And here is the result:




The JButton, JPanel, and JFrame actually have a ton of more options you can set.
Check out the Java documentation for the whole deal. In this simple example,
clicking the button does nothing, but clicking the "X" at the top right automatically
exits the program completely.


Event Handlers

Now to put something behind this simple little GUI that we have built.
Functionality can be added to clickable GUI components through event handlers.
This is done by adding a listener object to a component. Whenever any action is
done on the component, the appropriate listeners are triggered and their
appropriate methods (event handlers) are invoked. To see how this works, let's
modify the example above:

import java.lang.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


class SimpleGui2 {
  private static JFrame fr = null;
  private static JButton btn = null;


  public static void main(String args[]) {
    // Let's make a button first
    btn = new JButton("Click Me!");
    btn.setMnemonic(KeyEvent.VK_C); // Now you can hit the button with Alt-C
        btn.addActionListener(new ButtonListener()); // Allow the button to disable itself


        // Let's make the panel with a flow layout.
        // Flow layout allows the components to be
        // their preferred size.
        JPanel pane = new JPanel(new FlowLayout());
        pane.add(btn); // Add the button to the pane


        // Now for the frame
        fr = new JFrame();
        fr.setContentPane(pane); // Use our pane as the default pane
        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exit program when frame is closed
        fr.setLocation(200, 200); // located at (200, 200)
        fr.pack();             // Frame is ready. Pack it up for display.
        fr.setVisible(true);       // Make it visible
    }


    // Button event handler
    static class ButtonListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            btn.setEnabled(false); // Disable the button
        }
    }
}
Now this brings up the same window that the first one did. However, if you click
the button, it disables itself:




To see something a lot more complex, check out my preliminary design for the
TCP chat program: Gui.java. The GUI looks like this:
Try clicking the connect and disconnect buttons and see what happens. This
program is a lot simpler than the actual TCP chat program which you will see
later.


Thread Issues

Going from AWT to Swing results in a little issue with threads. All AWT classes
are thread safe; Swing's classes are not. A little knowledge about threads is
necessary to completely understand the reason for the complexity of using
threads. Sun's Java Tutorial covers this topic very well, so you might want to take
a peek there. Consider an object that has been instantiated in one thread. Now
this object needs to be modified by two or more threads. Data can easily be
corrupted if two threads try to modify the same object at the same time. Of
course, you know there is no such thing as "the same time" when it comes to
threads since the operating system switches between the various threads to
make them seem like they are running concurrently. However, if one thread is
interrupted while it is modifying an object and a second thread is initiated so that
it begins to modify that object, data can get corrupted.
There are a couple of ways to get around this problem in Java. Java allows a
way to enforce that no thread modifies the same object that your thread is
modifying through the use of the synchronize keyword. You can read up about it in
Sun's Java tutorial since it is out of the scope of this tutorial. Synchronizing an
object before modifying it blocks any other threads attempting to access the
synchronized   object until your synchronize block is done. AWT's methods synchronize
on their corresponding object instantiation, which prevents the objects (eg.
buttons, panels, etc.) on the screen from being corrupted while they are being
drawn. However, this can block your thread if it is trying to access the AWT
object. This just slows things down. For more information on threads and
synchronization, click here.


Swing and Threads

Swing, as I mentioned above, is not thread-safe. This means that most of its
methods do not synchronize with the internal state of the Swing object. Only a
few functions that are marked as thread-safe in the Java documentation are safe
to execute from anywhere. The programmer is now given the responsibility of
making sure that there are no thread conflicts. This can be done by making sure
that all the modifications to the Swing objects happen in the same thread. All the
events - such as button clicks and others - are handled on the thread known as
the event-handling thread. This thread is also where all the component painting
onto the screen is done. Hence, any modifications to the visible Swing
components can be made in any event handling routine. For example, in the
SimpleGui2   class above, the properties of the button are modified in the
ButtonListener   class, whose method is executed on the event-handling thread
every time the button is clicked.
Now, what if you have to modify an object without receiving any events? Swing
allows you to run a class that implements the Runnable interface on the event-
handling thread. This is done using the SwingUtilities.invokeLater(runnableObj);
method. For example, runnableObj is an instantiation of a class that implements
the Runnable interface. SwingUtilities.invokeLater(runnableObj); will queue the
runnableObj.run()   method on the event-handling queue, and the method will
eventually execute and be able to modify the Swing components. If you see the
TCPChat   code, you will see that that is exactly what I have done to update the GUI
with the state of the program. For more information and examples with Swing
and threads, click here.



TCP Chat Program

The chat program is in TCPChat.java. It implements both the client and the server
side, which is not too hard, since both use the Socket class. It would take much
too long to detail every portion of the program, so I will just tell you how to use it,
and you can check out the code to see how its done.
Firstly, this is what the final product looks like:




When two people want to chat using this program, each has to have an instance
of it running on his/her computer. This program will also work with two instances
on the same computer through localhost, as mentioned above in the TCP Sockets
section. To use the chatting program, do the following:

      Select the host option on one and the guest option on the other. Make sure that the port
       numbers are the same.
      For the guest, type in the IP address/name of the computer running the host in the Host
       IP text field.
      Now, click the "Connect" button on the host followed by the "Connect" button on the
       guest. If everything goes fine, both should be connected.
      Type the outgoing messages in the text field right below the text area on the right. Any
       incoming/outgoing messages will displayed in the text area.
      To disconnect, click the "Disconnect" button.
      To exit, click the "X" on the top-right of the window.
Links and More Information

All of my information is directly from Sun's Java 2 Documentation, and Java
Tutorial, both of which are accessible at Sun's Java home page. Here is a list of
useful links:

      Sun's Java home page
      Java Documentation
      Java Tutorial
      Java Tutorial - Getting Started
      JDK Download Page

								
To top