CM10135 / Programming II:   Lecture 12


How to Network



I.  Buffering

  1. A buffer is a piece of memory that holds a local copy of something that you really want to read or write to somewhere else.
  2. The reason you have them is so that you don't waste too much time waiting on slow processes, like writing or reading from a disk or network.
  3. You have probably seen a little bar representing a buffer fill up when you run a video from the internet, e.g. on quicktime. 
    1. For quicktime, when the buffer seems to be full enough that you can probably watch to the end of the movie, it lets you start seeing the movie.
    2. But if the network gets unexpectly worse / slower, then the movie will stop & you will have to wait until the buffer refills.
  4. Because writing is often buffered, if you want to make sure that what you have written has gone to the screen, you have to give a command to flush the buffer (see code below).
    1. This is also a big issue if you add printlines to debug a program.  Be sure to flush them right away, or the program may crash before the message you wanted to print get sent to the screen, even if the printline was executed succesfully.

II.  Reading & Writing Across Sockets (from last time, but we didn't get to it)

  1. These examples are taken from Learning Java
  2. You might also want to see Learning Java's complete sample programs for clients & servers, though there will be more examples further below, too.
  3. Notice that most of the code below is showing various ways to read & write to the socket, only one of which you'll need for coursework 2.
  4. Notice also though that you have to be careful to always read & write in the right order!
  5. It may still be easiest to use more than one socket...
// these examples are taken from Learning Java, pp. 335--337

// to open a client socket, we need to name the machine & the port the
// socket will be on. We also have to catch a couple exceptions...

try {
Socket sock = new Socket ("wupost.wustl.edu", 25);
} catch (UnknownHostException e) {
System.out.println("Can't find host.");
} catch ( IOException e) {
System.out.println("Error connecting to host.");
}

// Here's a client that reads & writes!

try {
Socket server = new Socket("foo.bar.com", 1234);
InputStream in = server.getInputStream();
Output Stream out = server.getOutputStream();

// write a byte
out.write(42);

// write a newline or carriage return delimited string
PrintWriter pout = new PrintWriter (out, true);
pout.println("Hello!");

//read a byte
byte back = (byte) in.read();

// read a newline or carriage return delimited string
BufferedReader bin =
new Buffered Reader (new Input StreamReader(in));
String response = bin.readLine();

// send a serialized java object
ObjectOutputStream oout = new ObjectOutputStream (out);
oout.writeObject(new java.util.Date());
oout.flush();
server.close();
} catch (IOException e) {...} // every one of these operations could have died!


// server code (for the same conversation! Notice these have to be in
// order...)

// assume this is running on the machine foo.bar.com

try {
// note: ServerSocket is a subclass of Socket that knows how to listen...
ServerSocket listener = new ServerSocket (1234);

while (!finished) {
Socket client = listener.accept (); // this waits for a connection

InputStream in = client.getInputStream();
OutputStrewam out = client.getOutputStream();

// read a byte
byte = someByte = (byte)in.read();

// read a newline or carriage-return-delimited string
BufferedReader bin =
new BufferedReader(new InputStreamReader(in));
String someString = bin.readLine();

// write a byte
out.write(43);

// say goodbye
PrintWriter pout = new PrintWriter (out, true);
p.out.println("Goodbye!");

// read that serialized Java object
ObjectInputStream oin = new ObjectInputStream(in);
Date date = (Date)oin.readObject();

client.close();
}

listener.close();

} catch (IOException e) {...}
catch (ClassNotFoundException e2) {...}


II. Clients for the date & echo services:

  1. In order to make clients and servers more clear to you, here are some examples.
  2. The example client is a program called telnet, which is a generic client which can connect to any service. 
    1. The thing is, you have to type in the side of the protocol that the server expects.
    2. That's because telnet (being generic) won't know about it.
  3. The example servers are standard internet services, which are provided by at least unix / linux computers.
  4. Since there are a lot of different actors in these examples I'm using colour coding.
    1. Sorry if you are colour blind.  You can try looking at the html source to see which colours I used!
    2. Green is me.
    3. Blue is the telnet program.
    4. Reds & oranges are the servers (there are different ones.)
    5. Black is the unix shell.  (the operating system)
  5. However, for security reasons, many of these services are by default turned off these days.
  6. If you have installed linux on your own computer, you might want to turn these on & play with them. 
    1. However, note that you should probably turn them back off again before plugging your computer back into the internet if you do!
    2. Note that this has to be your own linux box, because you need superuser (root) access to do this.
      1.  If you don't know what this means don't worry -- there are other examples below that don't require this, that you can run, like the linelength server.
      2. But do still have a look at what the servers do, so you can understand the code of what a client does that talks to it.
    3. Here's what I had to do to turn them on for my linux box:
      [root@sydney etc]# telnet localhost 7
      Trying 127.0.0.1...
      telnet: connect to address 127.0.0.1: Connection refused
      [root@sydney etc]# /sbin/chkconfig daytime on
      [root@sydney etc]# telnet localhost 15
      Trying 127.0.0.1...
      telnet: connect to address 127.0.0.1: Connection refused
      [root@sydney etc]# less services # this let me see what the different services were & find the right number
      [root@sydney etc]# telnet localhost 13
      Trying 127.0.0.1...
      Connected to localhost.
      Escape character is '^]'.
      17 MAR 2004 21:50:15 GMT
      Connection closed by foreign host.
      [root@sydney etc]# less services
      [root@sydney etc]# /sbin/chkconfig echo on
      [root@sydney etc]# telnet localhost 7
      Trying 127.0.0.1...
      Connected to localhost.
      Escape character is '^]'.
      hi
      hi
      golf
      golf
      ^]
  7. Notice a couple of things here:
    1. I've tapped into the server with a program called "telnet".  
      1. Telnet basically just lets you talk to ports directly. 
      2. It used to be used to login for sessions, but it's too insecure.  Nowadays we use ssh instead.
      3. I'll be showing you how you can use telnet to fake internet / application protocols in the next lecture.
    2. Mostly because of security, but also because in class I won't be networked, I'm talking to my own machine as if it's a machine on the internet.
      1. Your own machine can be accessed with the special IP address 127.0.0.1
      2. it's DNS name is "localhost" (as well as any other name you've given it.)
      3. Again, I'll probably explain DNS & how the internet routes packets this afternoon.
    3. I happen to be in the /etc directory, so the file that tells you the right port number for things is just "services".
    4. I have to be root to turn the services on.
  8. The first server kicked me out after giving me the information it gives --- I didn't have to type anything at all.
  9. The second server responded to what I typed.  But then I wanted to talk to telnet again (to quit) so I had to type ^].
  10. Assuming you can find a computer that will let you talk to its daytime server, then you can run this program (which is taken with only a slight modification from Object-Oriented Programming with Java by David Barnes, Chapter 19 (on Networking!):
    import java.net.*;
    import java.io.*;

    // Contact the daytime server running on hostname.
    public class DaytimeClient {
    // Contact the server at the appropriate port and set
    // the socket attribute for the run() method to use.
    public DaytimeClient(String hostname) throws Exception {
    // The well-known port of the TCP daytime service.
    final int DaytimePort = 13;
    try{
    socket = new Socket(hostname,DaytimePort);
    }
    catch(UnknownHostException e){
    throw new Exception("Unknown host: "+e.getMessage());
    }
    catch(IOException e){
    throw new Exception("IOException on socket creation: "+e.getMessage());
    }
    }

    // Obtain the time of day from the daytime server.
    public void run() {
    Socket daytime = getSocket();
    try{
    // Get the stream used by the server to send data.
    InputStream inStream = daytime.getInputStream();
    // Wrap the stream in a BufferedReader.
    BufferedReader reader = new BufferedReader(
    new InputStreamReader(inStream));

    // The server will only send a single line.
    String response = reader.readLine();
    System.out.println(response);
    // Close the connection now it is finished with.
    daytime.close();
    }
    catch(IOException e){
    System.err.println(e.getMessage());
    }
    }

    protected Socket getSocket(){
    return socket;
    }

    private final Socket socket;

    public static void main(String[] args) {
    if(args.length == 1){
    try{
    DaytimeClient client = new DaytimeClient(args[0]);
    client.run();
    }
    catch(Exception e){
    System.err.println("Exception: "+e.getMessage());
    }
    }
    else{
    System.err.println("You must supply the name of a host to contact.");
    }
    }
    }

  11. Here's one that talks to echo...

    /* author david barnes & joanna bryson
    *
    */
    import java.net.*;
    import java.io.*;


    // Contact the echo server running on hostname.
    class TCPEchoClient {
    // Contact the server at the appropriate port and set
    // the socket attribute for the run() method to use.
    public TCPEchoClient(String hostname) throws Exception {
    try{
    // The well-known port of the TCP echo service.
    final int EchoPort = 7;
    socket = new Socket(hostname,EchoPort);
    }
    catch(UnknownHostException e){
    throw new Exception("Unknown host: "+e.getMessage());
    }
    catch(IOException e){
    throw new Exception("IOException on socket creation: "
    +e.getMessage());
    }
    }

    protected Socket getSocket(){
    return socket;
    }

    private final Socket socket;


    public static void main(String[] args) {

    try {
    TCPEchoClient eClient = new TCPEchoClient("localhost");

    // now you know stdin is really a socket too!
    BufferedReader stdin =
    new BufferedReader(new InputStreamReader(System.in));
    String myEchoString;

    System.out.print("Welcome to the echo client. The prompt looks like >>."
    + "\n >> ");

    // Wrap the input stream in a BufferedReader.
    BufferedReader reader = new BufferedReader(
    new InputStreamReader(eClient.getSocket().getInputStream()));
    // Wrap the output stream in a BufferedWriter.
    BufferedWriter writer = new BufferedWriter(
    new OutputStreamWriter(eClient.getSocket().getOutputStream()));

    // read a string from stdin & send it to echo
    while ((myEchoString=stdin.readLine()) != null) {
    System.out.println("Sending: "+myEchoString);

    writer.write(myEchoString);
    writer.newLine();
    // Make sure the data is flushed to the stream.
    writer.flush();

    // Read the response.
    String response = reader.readLine();
    System.out.println("The response is: "+response);
    System.out.print("\n >> ");
    } // while strings
    // Close the connection
    eClient.getSocket().close();
    }
    catch(IOException ioe){
    ioe.printStackTrace();
    }
    catch(Exception e) {
    e.printStackTrace();
    }

    } // main()

    } // class TCPEchoClient
  12. Sorry I didn't color those creatively, but if you look at them in emacs (or eclipse) it should color them for you.
    1. If your BUCS unix server emacs isn't making pretty colors for you, you should put this in your .emacs file
      ; stick colour in old versions of emacs --

      ;; Are we running XEmacs or Emacs?
      (defvar running-xemacs (string-match "XEmacs\\|Lucid" emacs-version))

      ;; Turn on font-lock mode for Emacs
      (cond ((not running-xemacs)
      (global-font-lock-mode t)
      ))

      ; -- ( colour stuff from Adam Dziedzic ) --
    2. Notice:  emacs is written in lisp!
    3. You might want to look at ~cssjjb/.emacs for more random stuff

III. Servers

  1. There are a couple differences with servers:
    1. They have to start running first.
    2. They need an extra port -- one to listen for clients.
  2. But once a server has made the connection to the client, it's really just the same.
  3. Here is yet more code from David Barnes -- this time I left the main as he wrote it (in another class) because I'm going to demo this for you off the command line.
  4. The server class
    import java.net.*;
    import java.io.*;

    // A simple server that accepts a client connection
    // and sends back the length of the strings it
    // receives from the client.
    class LineLengthServer {
    public LineLengthServer(int port) throws Exception {
    try{
    // Listen on the given port.
    serverSocket = new ServerSocket(port);
    }
    catch(BindException e){
    throw new Exception("Failed to create a server socket: "+
    e.getMessage());
    }
    }

    // Read strings and return their length (as a String)
    // to the client.
    public void run() throws Exception {
    ServerSocket serverSocket = getServerSocket();
    Socket clientSocket = null;
    try{
    System.out.println("Listening for a client on port: "+
    serverSocket.getLocalPort());
    // Wait for a client to make contact.
    clientSocket = serverSocket.accept();
    // Contact ...
    System.out.println("A client has arrived.");

    // Wrap the input stream in a BufferedReader.
    BufferedReader reader = new BufferedReader(
    new InputStreamReader(clientSocket.getInputStream()));
    // Wrap the output stream in a BufferedWriter.
    BufferedWriter writer = new BufferedWriter(
    new OutputStreamWriter(clientSocket.getOutputStream()));

    // Read lines until the client terminates.
    String request = reader.readLine();
    while(request != null){
    // Write the length of the line as a String.
    writer.write(String.valueOf(request.length()));
    writer.newLine();
    writer.flush();
    request = reader.readLine();
    }
    }
    catch(IOException e){
    throw new Exception("IOException talking to the client: "+
    e.getMessage());
    }
    finally{
    if(clientSocket != null){
    System.out.println("The client has gone.");
    // Close the socket to the client.
    clientSocket.close();
    }
    }
    serverSocket.close();
    }

    protected ServerSocket getServerSocket(){
    return serverSocket;
    }

    // The socket on which the listening is done.
    private final ServerSocket serverSocket;
    }
  5. The "main" class
            // An example of a simple server that reads lines from
    // clients and sends back the length of each line
    // it receives.
    public class LineLengthServerMain {
    public static void main(String[] args){
    try{
    // An arbitrary port number to listen on. This should be
    // larger than 1024 for user-written servers.
    final int port = 24101;
    LineLengthServer server = new LineLengthServer(port);
    server.run();
    }
    catch(Exception e){
    System.err.println("Exception: "+e.getMessage());
    }
    }
    }

  6. Running it from linux
    [joanna@sydney Networks]$ javac LineLengthServerMain.java
    [joanna@sydney Networks]$ java LineLengthServer
    Exception in thread "main" java.lang.NoSuchMethodError: main
    [joanna@sydney Networks]$ java LineLengthServerMain
    Listening for a client on port: 24101
    ^Z
    [2]+ Stopped java LineLengthServerMain
    [joanna@sydney Networks]$ bg
    [2]+ java LineLengthServerMain &
    [joanna@sydney Networks]$ telnet localhost 24101
    Trying 127.0.0.1...
    A client has arrived.
    Connected to localhost.
    Escape character is '^]'.
    hi there
    8
    have you ever thought
    21
    this isn't really measuring the line length...
    46
    Ah ha!
    6
    ^]

    telnet> .
    ?Invalid command
    telnet> quit
    Connection closed.
    The client has gone.
    [2]+ Done java LineLengthServerMain
    [joanna@sydney Networks]$
    1. Notice I used telnet as a client again (see colour code mentioned earlier).
    2. And also, I stopped the server process (with ^Z) and then backgrounded it (made it run, but leave me stdin to use on another program).
    3. Consequently, both programs were printing to the screen at the same time -- telent I made blue, the server red, and what I typed green.
    4. I also forgot the telnet protocol / commands -- I thought you killed it with a .
  7. If you want to make a server accept more than one connection, just put a while loop in so it looks again (see the outlined server back in section I.)
  8. If you want to have the server accept new clients while it's still servicing old ones, you need to use threads!
  9. Here's an example of that, again from Barnes (hey, he writes good examples! This is from RandomServiceListener)
        public void listen() throws Exception {
    ServerSocket serverSocket = getServerSocket();
    // Wait up to 30 minutes for new clients.
    final int timeToWait = 1*60*1000;
    boolean keepWaiting = true;

    while(keepWaiting){
    try{
    // Wait for a client to make contact.
    serverSocket.setSoTimeout(timeToWait);
    Socket clientSocket = serverSocket.accept();
    // Let a separate Thread handle it.
    new Thread(new RandomService(clientSocket)).start();
    }
    catch(InterruptedIOException e){
    // We timed out waiting for a client.
    keepWaiting = false;
    }
    catch(IOException e){
    throw new Exception("IOException: "+ e.getMessage());
    }
    }
    // No more clients, so close the socket.
    serverSocket.close();
    }
    1. Notice not only the threading, but the fact it handles interupts, so it can eventually be killed!
    2. It also sets a timeout so that it will effectively interrupt itself if it's been waiting too long (as well as accepting terminate signals, e.g. from the keyboard.)

IV.  Finding out what your local machine's address is:

  1. Another useful program potentially for your coursework, again from David Barnes (the bit that matters is in blue):
    // Print out Internet address information about the local machine.
    import java.net.*;

    public class PrintInetDetails {
    public static void main(String[] args){
    if(args.length == 0){
    try{
    InetAddress myDetails = InetAddress.getLocalHost();
    System.out.println("The local host is called: "+
    myDetails.getHostName()+
    " and its address is: "+
    myDetails.getHostAddress());
    }
    catch(UnknownHostException e){
    System.err.println("Unknown host: "+e.getMessage());
    }
    }
    else{
    for(int i = 0; i < args.length; i++){
    try{
    InetAddress details = InetAddress.getByName(args[i]);
    System.out.println("The host is called: "+
    details.getHostName()+
    " and its address is: "+
    details.getHostAddress());
    }
    catch(UnknownHostException e){
    System.err.println("Unknown host: "+e.getMessage());
    }
    }
    }
    }
    }

  2. When/if I show it to you running on my laptop, it only says lamely the standard localhost address, but here's what it did on my desktop last year (alas, ai.mit.edu is no more!):
    [jjb@jjb Networks]$ java PrintInetDetails
    The local host is called: jjb.cs.bath.ac.uk and its address is: 172.16.33.1
    [jjb@jjb Networks]$ java PrintInetDetails horsepower.ai.mit.edu soggy-fibers.ai.mit.edu
    The host is called: horsepower.ai.mit.edu and its address is: 128.52.37.26
    The host is called: soggy-fibers.ai.mit.edu and its address is: 128.52.32.78
    [jjb@jjb Networks]$ java PrintInetDetails wjh.harvard.edu www.google.com
    The host is called: wjh.harvard.edu and its address is: 140.247.94.249
    The host is called: www.google.com and its address is: 66.102.11.99
  3. Notice that the two MIT AI lab addresses are very similar -- again, more on that in the protocols lecture.

V. Summary

  1. Mostly a lot of examples of clients & servers
  2. A little bit of a feel for how to use unix/linux, and how telnet can be used to fake one side of a client.
  3. Next lecture, no code, just how stuff works.

page author: Joanna Bryson
6 March 2006