Java Network Programming

This week we are going to learn about using Java to move data and files across a network. You will not have a networking class until next Fall (IC322) but we are going to have to learn a little network theory for this to make sense.

A little network theory

Computer networks are fascinating and complex systems. There is probably nobody on the planet who knows everything about how a network works. In order to make them easier to understand and operate, network engineers have broken their functions down into layers. The following table describes the "OSI 7-Layer model":

LayerNameDescription
7 Application Allows two applications to exchange information. e.g. HTML
6 Presentation (Usually treated as part of Layer 7)
5 Session (Usually treated as part of Layer 7)
4 Transport End-to-end communications between two remote computers. Provides reliability. e.g. TCP
3 Network Multi-hop path determination and addressing. e.g. IP
2 Data Link Allows communication between two adjacent nodes, such as between a single computer and its nearest switch, or a wireless laptop and its wireless access point. e.g. Ethernet or 802.11g
1 Physical This Layer describes the actual medium through which the network messages travel. e.g. copper wires or radio waves

Most software engineers program at Layer 7 (Application). This is where user programs such as Internet browsers and chat clients live. At this layer, we just use the underlying network as a communications tool. If you are programming on a lower layer, you are developing the network itself.

Layers 5 & 6 are notional only. Most network models wrap them into Layer 7. For our purposes, we will ignore them.

Each layer uses the layers below it as building blocks. In order to be a Layer-7 programmer, you need to know the fundamentals of Layers 4 and 3. (Again - we are ignoring Layers 5 & 6.)

Layer 4 - Transport Layer

TCP (Transport Control Protocol) is one of the most popular protocols in Layer 4. TCP provides two import functions. `

First, TCP provides reliable end-to-end communications between two computers. By "reliable", we mean that if a message is lost along the way, the TCP drivers will automatically retransmit it until it gets through. They will also tell you if the remote machine is unavailable. Using TCP is a lot like sending a package and getting a receipt back that says it was received on the other end.

Second, TCP messages contain a "port number" (or "socket" number). There are many programs running on a single computer. A port number indicates which program each message refers to. Imagine that you have both Firefox and Internet Explorer open at the same time. If you request a webpage in Firefox, then you expect it to display it self in the same program. It would be confusing if you requested a page in Firefox and it displayed in Internet Explorer. Since both browsers are running, how does your computer know where to send each incoming webpage? Each program has a different socket number. Browsers will usually have several sockets open at the same time. Your computer keeps a table of which applications are using which sockets. When a new message comes in, your computer will read its socket number, look up the appropriate application in a table, and send it to the intended recipient.

Layer 3 - Network Layer

IP (Transport Control Protocol) is one of the most popular protocols in Layer 3.

IP moves a single message from one computer to another. It provides navigation for multiple hops through a network, across switches and routers.

Each networked machine has a unique IP address, made up of 4 chars (0..255) separated by periods. This is called a "dotted-quad" format. The IP address for www.usna.edu is 136.160.88.139.

Addressing with both IP and port numbers

Try this:

  1. Type http://136.160.88.139 into a browser. The browser should take you to USNA's homepage.
  2. Type http://136.160.88.139:80 into a browser. The browser should take you to USNA's homepage again. What is different? The ":80" tells the browser that it should request port 80 on the remote server. By convention, webservers listen for traffic on port 80. Why did we not need the ":80" on the first request? Because your browser knows this is the standard webserver listening port and added it in automatically.
  3. Type http://136.160.88.139:6000 into a browser. The webpage should not come up. There is no webserver running on that port. When this request get to the Academy's webserver, that computer does not know what program to deliver the message to.

There are 65,536 unique port numbers available on each computer. Many are commonly used for specific functions such as http, https, email, ssh, etc. There is a comprehensive list here: Common Port numbers

Network programming in Java

Java, as you might expect, has some classes to help simplify network programming.

First, lets meet a tool that makes it easy to retrieve a webpage:java.net.URL. There are many contructors there. For our purposes, here is the most useful one:

  URL google=new URL("http://www.google.com");

Note - you have to surround this with a try/catch block to catch a MalformedURLException. Almost any method that communicates with the world outside your own program will require exception-handling.

Now, supposing that the website is reachable - what’s next? Ideally, we would want some way of getting that information back to the user(or us). We could do this two ways: I’m choosing the easiest.

You may remember InputStream from previous labs that needed to read data from a file. "InputStream" and "OutputStream" are classes that let us abstract any data flow in or out of our programs. They work across files systems, neworks, and other IO devices.

  google.openStream()...

Now we can use Scanner to do the rest:

  Scanner scan=new Scanner(oracle.openStream());

Here is an entire program for reading a webpage and dumping it to the screen:

  import java.net.URL;
  import java.net.MalformedURLException;
  import java.util.Scanner;
  import java.io.IOException;

  public class URLReader{

    public static void main(String[] args){

      try{
        URL oracle=new URL("http://www.google.com");
        Scanner scan=new Scanner(oracle.openStream());

        while(scan.hasNext())
          System.out.println(scan.next());
      } catch(MalformedURLException mUE){
        System.out.println(mUE.getLocalizedMessage());
      }catch(IOException iOE){
        System.out.println(iOE.getLocalizedMessage());
      }
    }
  }

If you run this, what you get back is the HTML that makes up the page, so it may not be immediately clear to you what the page looks like. However, we've successfully gotten the information from the web server to our computer. Java does have classes to display this: we will learn them shortly....

Try some other URLs, and see what you get.

URL programming has many uses. One of the most useful is REST interfaces (REpresentational State Transfer). By this mechanism, you can query a http source for data. There are several common formats, like XML and JSON. This gives you the ability to separate your data storage and retrieval code from your processing code. You can even retrieve a webpage from one server and fill it in with data from another. You could write an application that runs in California to store and retrieve your data, while your “working” code can run right here. Distributed programming, eh?

You could even Serialize objects over this type of connection. You couldn’t use Scanner, of course, but using an ObjectInputStream with a Serializable object, you can make it work.

So where do sockets fit in?

The URL example above uses the default port 80. What if we want to send and receive data that is not a webpage?

Sockets are the middle level of network programming: force a connection between two computers, then start throwing messages back and forth. The big difference between URL and Sockets is the assumption with Sockets that you WILL be talking in two ways: URLs only assume you will send a simple request in the url to the server, and receive the response. Semantically similar, but much different in application.

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

  public class EchoClient {
    public static void main(String[] args){
      //All of this gets the hostname of the server
      Scanner console = new Scanner(System.in);
      String hostname;
      if (args.length != 1) {
        System.err.println("Please enter a server hostname.");
        hostname = console.next();
        console.nextLine();
      } else {
        hostname = args[0];
      }

      Socket echoSocket = null;
      PrintWriter out = null;
      Scanner in = null;

      try {
        //Create a socket connected to hostname at port 4444
        echoSocket = new Socket(hostname, 4444);
        //Create a PrintWriter writing to the socket's OutputStream
        out = new PrintWriter(echoSocket.getOutputStream(), true);
        //Create a Scanner listening to the socket's InputStream
        in = new Scanner(echoSocket.getInputStream());

        System.out.print("Enter some text: ");
        //Type in a line of text
        String userInput = console.nextLine();
        //While that text isn't the word exit,
        while (!userInput.toUpperCase().equals("EXIT")) {
          //Write that text to the PrintWriter, which sends it to the server
          out.println(userInput);
          //Get text back from the server, and print it to the console
          System.out.println("From server: " + in.nextLine());
          //Type in more text
          System.out.print("Enter some text: ");
          userInput = console.nextLine();
        }
        //Send the word "EXIT" to the server
        out.println("EXIT");
        //Close everything
        echoSocket.close();
        out.close();
        in.close();
      } catch (UnknownHostException e) {
        System.err.println("Don't know about host: " + hostname);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

You can see the basics for the Socket connection:

  1. Create a new Socket hooked to a host and port
  2. Connect its output stream to some kind of stream writer (PrintWriter, in this case)
  3. Connect its input stream to read from a stream reader- here, a Scanner

Java, being a bit more object oriented than many languages, also has some neat helper classes that mimic this behavior. One of the most useful is ServerSocket. Despite its name, it doesn’t extend Socket: in itself, it doesn’t really act like a socket, but is Socket-like.

Here’s the most useful thing it does.

Yes, that’s right: this class’ job is to open a port on a host waiting for other Sockets to contact it. When they do, the accept function returns a Socket that you can use to communicate back and forth....

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

  public class EchoServer {
    public static void main(String[] args) {
      ServerSocket server = null;
      Socket client = null;
      PrintWriter out = null;
      Scanner in = null;
      try {
        server = new ServerSocket(4444); // build a ServerSocket at port 4444
        client = server.accept(); // when someone connects to that ServerSocket,
                                  // create the relevant Socket talking to them
        System.out.println("Connected!");
        //Create a PrintWriter that is writing to the socket's OutputStream
        out = new PrintWriter(client.getOutputStream(), true);
        //Create a Scanner that is listening to the socket's InputStream
        in = new Scanner(client.getInputStream());
        //Get a line from the Scanner
        String inStr = in.nextLine();
        while (inStr != null) {
          //If the client requested an exit, stop all this
          if (inStr.equals("EXIT"))
            break;
          //print the line we got from the client
          System.out.println(inStr);
          //concatenate "Hi," onto what the sent, and write it back to them
          out.println("Hi, " + inStr);
          //get another line from the client
          inStr = in.nextLine();
        }
        //Close everything
        server.close();
        client.close();
        out.close();
        in.close();
      } catch (IOException e) {
        System.out.println("Could not listen on port 4444");
      }
    }
  }

As before, we are hooking our Sockets to text streams: we don’t have to do that. You could connect them to ObjectStreams and send Serializable classes over the network between two hosts. In fact, if you’ve ever heard of Java Messaging Services, thats exactly what happens.

The previous two topics were of connection-based networking: you force a connection from client to server, and communicate back and forth. So far we have only mentioned TCP for Layer-4 protocols. There is another protocol called UDP, which does not create a connection or provide reliability. Java has an implementation of this as well-the DatagramSocket. We won’t go much into this here, as its at a very low level of implementation, but there is an interesting class that descends from a DatagramSocket- the MulticastSocket, which, as it implies, allows you to send to multiple sockets at once. You can create your own group chat room using this guy!

Java does have more functions that allows you to peek into the network parameters. As you move along in your career, you should check the functionality of java out more..

Suggested Practice