Java Networking

Java's socket-based communications allow applications to view networking as if it were file I/O, a program can read and write to a socket as if it were a file. Java provides stream (TCP) and datagram sockets (UDP).

Stream sockets a process establishes a connection to another process, while the connection is in place data flows between the processes in continuous streams. Stream sockets are said to provide a connection-oriented service (TCP).
Datagram sockets individual packets of information are transmitted, these packets are sent via a connectionless service, this means that packets can be lost, duplicated, out of order when they arrive at the destination. This means that extra programming is required at the client end to sort out these problems.

Connectionless services generally offer greater performance but less reliability than connection-oriented sevices

Manipulating URLs

The world wide web (www) uses URLs (Uniform Resource Locators, also called Universal Resource Locators) to locate data on the Internet.

URL examples www.datadisk.co.uk
www.datadisk.co.uk/images
www.google.com
www.sun.com
www.theregister.co.uk

Using http you can access the above web sites, Java has the ability to manipulate URLs.

URL code example
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.applet.AppletContext;


public class SiteSelector extends JApplet {
   private Hashtable sites;
   private Vector siteNames;

   public void init()
   {
      sites = new Hashtable();
      siteNames = new Vector();

      getSitesFromHTMLParameters();

      Container c = getContentPane();
      c.add( new JLabel( "Choose a site to browse" ),
             BorderLayout.NORTH );

      final JList siteChooser = new JList( siteNames );
      siteChooser.addListSelectionListener(
         new ListSelectionListener() {
            public void valueChanged( ListSelectionEvent e )
            {
               Object o = siteChooser.getSelectedValue();
               URL newDocument = (URL) sites.get( o );
               AppletContext browser = getAppletContext();
               browser.showDocument( newDocument );
            }
         }
      );
      c.add( new JScrollPane( siteChooser ),
             BorderLayout.CENTER );
   }

   private void getSitesFromHTMLParameters()
   {
      // look for applet parameters in the HTML document
      // and add sites to Hashtable
      String title, location;
      URL url;
      int counter = 0;

      while ( true ) {
         title = getParameter( "title" + counter );

         if ( title != null ) {
            location = getParameter( "location" + counter );
            
            try {
               url = new URL( location );
               sites.put( title, url );
               siteNames.addElement( title );
            }
            catch ( MalformedURLException e ) {
               e.printStackTrace();
            }
         }
         else
            break;

         ++counter;  
      }
   }
}

## HTML Code

<APPLET CODE = "SiteSelector.class" WIDTH = 300 HEIGHT = 75>
<PARAM NAME = "title0" VALUE ="Java Home Page">
<PARAM NAME = "location0" VALUE ="http://java.sun.com/">
<PARAM NAME = "title1" VALUE ="Deitel">
<PARAM NAME = "location1" VALUE ="http://www.deitel.com/">
<PARAM NAME = "title2" VALUE ="Gamelan">
<PARAM NAME = "location2" VALUE ="http://www.gamelan.com/">
<PARAM NAME = "title3" VALUE ="JavaWorld">
<PARAM NAME = "location3" VALUE ="http://www.javaworld.com/">

Reading a File on a Web Server

You can read plain text or HTML formated text, thus you could create your own simple web browser

Example
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;


public class ReadServerFile extends JFrame {
   private JTextField enter;
   private JEditorPane contents;

   public ReadServerFile()
   {
      super( "Simple Web Browser" );

      Container c = getContentPane();

      enter = new JTextField( "Enter file URL here" );
      enter.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               getThePage( e.getActionCommand() );
            }
         }
      );
      c.add( enter, BorderLayout.NORTH );

      contents = new JEditorPane();
      contents.setEditable( false );
      contents.addHyperlinkListener(
         new HyperlinkListener() {
            public void hyperlinkUpdate( HyperlinkEvent e )
            {
               if ( e.getEventType() ==
                    HyperlinkEvent.EventType.ACTIVATED )
                  getThePage( e.getURL().toString() );
            }
         }
      );
      c.add( new JScrollPane( contents ),
             BorderLayout.CENTER );

      setSize( 400, 300 );
      show();
   }

   private void getThePage( String location )
   {
      setCursor( Cursor.getPredefinedCursor(
                    Cursor.WAIT_CURSOR ) );

      try {
         contents.setPage( location );
         enter.setText( location );
      }
      catch ( IOException io ) {
         JOptionPane.showMessageDialog( this,
            "Error retrieving specified URL",
            "Bad URL",
            JOptionPane.ERROR_MESSAGE );
      }

      setCursor( Cursor.getPredefinedCursor(
                    Cursor.DEFAULT_CURSOR ) );
   }

   public static void main( String args[] )
   {
      ReadServerFile app = new ReadServerFile();

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );
   }
}

Establishing a Simple Server (Using Stream Sockets)

There are five steps to create a simple server in Java

  1. Create a Server-Socket object (specifiy a port, maximum clients that can connect called queueLength)
  2. Listen for clients that want to connect
  3. Get the OutputStream and Inputstream objects that enable the server to communicate with the client
  4. Is the processing phase in which the server and the client communicate via the OutputStream and InputStream objects
  5. Closing the socket when finished, thus ending communication
Simple Server
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class Server extends JFrame {
   private JTextField enter;
   private JTextArea display;
   ObjectOutputStream output;
   ObjectInputStream input;

   public Server()
   {
      super( "Server" );

      Container c = getContentPane();

      enter = new JTextField();
      enter.setEnabled( false );
      enter.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               sendData( e.getActionCommand() );
            }
         }
      );
      c.add( enter, BorderLayout.NORTH );

      display = new JTextArea();
      c.add( new JScrollPane( display ),
             BorderLayout.CENTER );

      setSize( 300, 150 );
      show();
   }

   public void runServer()
   {
      ServerSocket server;
      Socket connection;
      int counter = 1;

      try {
         // Step 1: Create a ServerSocket.
         server = new ServerSocket( 5000, 100 );

         while ( true ) {
            // Step 2: Wait for a connection.
            display.setText( "Waiting for connection\n" );
            connection = server.accept();
            
            display.append( "Connection " + counter + " received from: " + 
                                 connection.getInetAddress().getHostName() );

            // Step 3: Get input and output streams.
            output = new ObjectOutputStream( connection.getOutputStream() );
            output.flush();
            input = new ObjectInputStream( connection.getInputStream() );
            display.append( "\nGot I/O streams\n" );
 
            // Step 4: Process connection.
            String message = "SERVER>>> Connection successful";
            output.writeObject( message );
            output.flush();
            enter.setEnabled( true );

            do {
               try {
                  message = (String) input.readObject();
                  display.append( "\n" + message );
                  display.setCaretPosition( display.getText().length() );
               }
               catch ( ClassNotFoundException cnfex ) {
                  display.append( "\nUnknown object type received" );
               }
            } while ( !message.equals( "CLIENT>>> TERMINATE" ) );

            // Step 5: Close connection.
            display.append( "\nUser terminated connection" );
            enter.setEnabled( false );
            output.close();
            input.close();
            connection.close();

            ++counter;
         }
      }
      catch ( EOFException eof ) {
         System.out.println( "Client terminated connection" );
      }
      catch ( IOException io ) {
         io.printStackTrace();
      }
   }

   private void sendData( String s )
   {
      try {
         output.writeObject( "SERVER>>> " + s );
         output.flush();
         display.append( "\nSERVER>>>" + s );
      }
      catch ( IOException cnfex ) {
         display.append( "\nError writing object" );
      }
   }

   public static void main( String args[] )
   {
      Server app = new Server();

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

      app.runServer();
   }
}

Establishing a Simple Client (Using Stream Sockets)

Simple Client
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class Client extends JFrame {
   private JTextField enter;
   private JTextArea display;
   ObjectOutputStream output;
   ObjectInputStream input;
   String message = "";

   public Client()
   {
      super( "Client" );

      Container c = getContentPane();

      enter = new JTextField();
      enter.setEnabled( false );
      enter.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               sendData( e.getActionCommand() );
            }
         }
      );
      c.add( enter, BorderLayout.NORTH );

      display = new JTextArea();
      c.add( new JScrollPane( display ), BorderLayout.CENTER );

      setSize( 300, 150 );
      show();
   }

   public void runClient() 
   {
      Socket client;

      try {
         // Step 1: Create a Socket to make connection.
         display.setText( "Attempting connection\n" );
         client = new Socket( InetAddress.getByName( "127.0.0.1" ), 5000 );

         display.append( "Connected to: " + client.getInetAddress().getHostName() );

         // Step 2: Get the input and output streams.
         output = new ObjectOutputStream( client.getOutputStream() );
         output.flush();
         input = new ObjectInputStream( client.getInputStream() );
         display.append( "\nGot I/O streams\n" );

         // Step 3: Process connection.
         enter.setEnabled( true );

         do {
            try {
               message = (String) input.readObject();
               display.append( "\n" + message );
               display.setCaretPosition( display.getText().length() );
            }
            catch ( ClassNotFoundException cnfex ) {
               display.append( "\nUnknown object type received" );
            }
         } while ( !message.equals( "SERVER>>> TERMINATE" ) );

         // Step 4: Close connection.
         display.append( "Closing connection.\n" );
         output.close();
         input.close();
         client.close();
      }
      catch ( EOFException eof ) {
         System.out.println( "Server terminated connection" );
      }
      catch ( IOException e ) {
         e.printStackTrace();
      }
   }

   private void sendData( String s )
   {
      try {
         message = s;
         output.writeObject( "CLIENT>>> " + s );
         output.flush();
         display.append( "\nCLIENT>>>" + s );
      }
      catch ( IOException cnfex ) {
         display.append( "\nError writing object" );
      }
   }

   public static void main( String args[] )
   {
      Client app = new Client();

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

      app.runClient();
   }
}

Connectionless Client/Server Interaction with Datagrams

Connectionless communication is like breaking up a letter and send each part of a letter in the post, each letter could arrive out of turn, but once all the letters have arrived they can be pieced backed together to produce the complete letter. On a occation a letter may go missing so you resend it, but as you can see the client has to perform additional work to piece all the pieces together.

Server Example
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class Server extends JFrame {
   private JTextArea display;

   private DatagramPacket sendPacket, receivePacket;
   private DatagramSocket socket;

   public Server()
   {
      super( "Server" );

      display = new JTextArea();
      getContentPane().add( new JScrollPane( display),
                            BorderLayout.CENTER );
      setSize( 400, 300 );
      show();

      try {
         socket = new DatagramSocket( 5000 );
      }
      catch( SocketException se ) {
         se.printStackTrace();
         System.exit( 1 );
      }
   }

   public void waitForPackets()
   {
      while ( true ) {
         try {
            // set up packet
            byte data[] = new byte[ 100 ];
            receivePacket =
               new DatagramPacket( data, data.length );

            // wait for packet
            socket.receive( receivePacket );
 
            // process packet
            display.append( "\nPacket received:" +
               "\nFrom host: " + receivePacket.getAddress() +
               "\nHost port: " + receivePacket.getPort() +
               "\nLength: " + receivePacket.getLength() +
               "\nContaining:\n\t" +
               new String( receivePacket.getData(), 0,
                           receivePacket.getLength() ) );

            // echo information from packet back to client
            display.append( "\n\nEcho data to client...");
            sendPacket =
               new DatagramPacket( receivePacket.getData(),
                                   receivePacket.getLength(),
                                   receivePacket.getAddress(),
                                   receivePacket.getPort() );
            socket.send( sendPacket );
            display.append( "Packet sent\n" );
            display.setCaretPosition(
               display.getText().length() );
         }
         catch( IOException io ) {
            display.append( io.toString() + "\n" );
            io.printStackTrace();
         }
      }
   }

   public static void main( String args[] )
   {
      Server app = new Server();

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

      app.waitForPackets();
   }
}
Client Example
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class Client extends JFrame implements ActionListener {
   private JTextField enter;
   private JTextArea display;

   private DatagramPacket sendPacket, receivePacket;
   private DatagramSocket socket;

   public Client()
   {
      super( "Client" );

      enter = new JTextField( "Type message here" );
      enter.addActionListener( this );
      getContentPane().add( enter, BorderLayout.NORTH );
      display = new JTextArea();
      getContentPane().add( new JScrollPane( display ),
                            BorderLayout.CENTER );
      setSize( 400, 300 );
      show();

      try {
         socket = new DatagramSocket();
      }
      catch( SocketException se ) {
         se.printStackTrace();
         System.exit( 1 );
      }
   }

   public void waitForPackets()
   {
      while ( true ) {
         try {
            // set up packet
            byte data[] = new byte[ 100 ];
            receivePacket =
               new DatagramPacket( data, data.length );

            // wait for packet
            socket.receive( receivePacket );
 
            // process packet
            display.append( "\nPacket received:" +
               "\nFrom host: " + receivePacket.getAddress() +
               "\nHost port: " + receivePacket.getPort() +
               "\nLength: " + receivePacket.getLength() +
               "\nContaining:\n\t" +
               new String( receivePacket.getData(), 0,
                           receivePacket.getLength() ) );
               display.setCaretPosition(
                  display.getText().length() );
         }
         catch( IOException exception ) {
            display.append( exception.toString() + "\n" );
            exception.printStackTrace();
         }
      }
   }

   public void actionPerformed( ActionEvent e )
   {
      try {
         display.append( "\nSending packet containing: " +
                         e.getActionCommand() + "\n" );

         String s = e.getActionCommand();
         byte data[] = s.getBytes();

         sendPacket = new DatagramPacket( data, data.length,
            InetAddress.getLocalHost(), 5000 );
         socket.send( sendPacket );
         display.append( "Packet sent\n" );
         display.setCaretPosition(
            display.getText().length() );

      }
      catch ( IOException exception ) {
         display.append( exception.toString() + "\n" );
         exception.printStackTrace();
      }
   }

   public static void main( String args[] )
   {
      Client app = new Client();

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

      app.waitForPackets();
   }
}

Network Security

This is a vast topic and many books have been written about this subject, some of the examples we used are applets which themselves are dangerous, applets are downloaded from a web server and executed on your computer, anything could be in the payload, this is why some company web browsers will not allow applets to run. Java has a security API which will address some of the security related issues, I recommended you download the latest documentation from Sun and see what needs to be done in order to secure your application.

I hope to come back to this topic and hightlight some of the pitfalls and solutions, but first i must get my grounding in Java basics first.