Check out the new USENIX Web site.
Using JavaUSENIX

 

by Rik Farrow
rik@spirit.com

December, 1996

In the first column, I promised that I'd look for other ports to Java. I did find a few. The OSF has ports to HP/UX 10.01, DEC UNIX 3.2, Sony NeWs, and AIX 4.1 (for Bull). I don't have any of these platforms, but I know that DEC signed a license with Sun at the end of September. Try www.gr.osf.org/java/ javaport/JDK-1.0.1/.

There is also guava (don't laugh) at ftp://summit.stanford.edu/pub/guavac/guavac.tar.gz. Guavac is written for GCC 2.7.2 and will (probably) run under SunOS. There is also a precompiled binary for Linux there. I won't have time to try this before I leave for Iceland.

Networking Made Easy

The topic for this month is networking. I noticed Hal Pomeranz's coverage of Perl networking in his column and realized how much Perl networking looked like C. Not surprisingly, Java doesn't look at all like C.

For one thing, the Java developers were writing with one protocol in mind - TCP/IP. This eliminates the need to specify the protocol type when creating a socket. Also, Java provides input and output streams that make reading and writing, whether from a socket or a file, easy.

On the client side, you must create a socket, which requires the hostname and port addresses. The hostname must be a string and can also be the dotted decimal notation quoted to turn it into a string. Creating the socket will succeed if the host is reachable and has a server running on the given port.

Once the port is open, the client can get the socket's InputStream for reading or its OutputStream for writing. These streams permit reading one or more bytes of data. But wrapping these streams in other Input or OutputStream classes makes life easier.

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

public class DateClient { 
    public static final int PORT = 13;
    // the daytime port

    public static void main(String[] args) { 
        Socket s = null; 
        String line = null; 
            try { 
                // Create a socket 
                s = new Socket("localhost", PORT); 
                // Create stream for reading this socket. 
                DataInputStream sin = new 
                    DataInputStream(s.getInputStream());
                line = sin.readLine(); 
                if (line != null) System.out.println(line); 
            } 
            catch (IOException e) {System.err.println(e);}
            // Always be sure to close the socket 
                finally                         { 
                try ( if (s != null) s.close(); } 
                catch (IOException e2) ; 
            } 
    } 
}

This example, DateClient.java, creates a socket connected to the daytime port on the localhost. It could be fancier by accepting a command line argument for the hostname, but this example keeps things simple. If creating the socket is successful, you get its InputStream, and use it as the argument for creating a new DataInputStream. The advantage here is that you can read a line at a time from the DataInputStream as a string, then print it to the standard output, which is referenced by the System.out class variable. Being good citizens, we close the socket when we are finished.

The try and catch statements handle Exceptions, the Java (and C++) way of receiving error notification. If any statement within the curly braces following the try generates an IOException, the catch clause is executed immediately. The finally clause always gets executed, whether the catch clause does or not. The Java compiler enforces catching exceptions, so you will be reminded if you call a method that may throw an exception and you have forgotten to catch it.

DateServer

UNIX systems have a daytime server built into the inetd program. On most systems, the daytime server will not be disabled. Other internal servers, such as chargen (the character generator) and echo (pretty obvious) have been disabled on many UNIX systems because they can be abused by a denial of service attack.

If you don't have a daytime server, you can write your own in Java with a little effort. The server has more work to do than the client. You create a ServerSocket, and start a Thread that listens (using accept()) for connections. On a more complicated server, each connection would run in its own Thread. But all we want to do is return the date, which can be done quickly without a separate Thread.

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

public class DateServer extends Thread {

    public final static int PORT = 13; 
    protected ServerSocket listen_socket;

 // Create a ServerSocket to listen to; 
public DateServer() { 
    try { listen_socket = new ServerSocket(PORT); }
    catch (IOException e) { 
       System.err.println("Exception creating server"
                           + "socket: " + e); 
       System.exit(1); 
    } 
    // fire up the Thread's run() method 
    this.start(); 
}

In the constructor for the DateServer class, we create a new ServerSocket, catching any IOExceptions and exiting if they occur after printing an error message. The Thread is started with this.start(), passing execution to the Thread's run() method.

public void run() { 
    PrintStream out;
    try { 
        while(true) { 
            Socket client_socket = listen_socket.accept(); 
            try { out = new PrintStream(client_socket.getOutputStream()); 
            }
            catch (IOException e) { 
                try client_socket.close(); catch (IOException e2) ;
                System.err.println("Exception while getting"
                                + " socket streams: " + e);
                return; 
            } 
            out.println(new Date());
            client_socket.close(); 		} 
        //End of while(true) loop
    } catch (IOException e) { 
    // Any IOException in big loop
     	System.err.println("Exception while listening"
            + " for connections: " + e);
        System.exit(2); 
    } 
}

The run() method of the DateServer does the grunt work. The while loop blocks at the accept() method until a client connects. Then we get the OutputStream and wrap it in a PrintStream while checking for IOExceptions. Notice that the later catch could be used, but here we are sending a different error notation. Once the PrintStream is successfully created, we simply use the println() method to send the Date, after it has been converted to a string automatically by println() calling the toString() method for us. Again, we close the socket, return to the beginning of the loop, and block again listening.

A server that would take more than a few seconds to carry out its work should create another object, which has its own Thread to handle its conversation with the client.

// Start the server up, listening on an optionally specified port 
public static void main(String[] args) { 
		new DateServer(); 
	} 
}

The end of the DateServer class is a simple main() method that calls the DateServer() constructor and gets the ball rolling. Running this class will fail if you already have a daytime server. If you still want to experiment with it, change the PORT variable in both the client and the server.

Another Way

Like Perl, there are many ways to do things. Perl excels in string handling and output formatting, things that are rather weak in Java. Java has yet another way to handle networking. You can create URL objects and use them to talk to servers. But that's a topic for another day.

First published in ;login:, Volume 21, No. 6, December 1996.

 

?Need help? Use our Contacts page.
Last changed: May 16, 1997 pc
Java index
Publications index
USENIX home