Networking: Sockets


Simple one-way text messaging

We will write two simple programs:

What is a socket?

Let's look at an example. First, the sender: (source file)

import java.io.*;     // For PrintWriter.
import java.net.*;    // For Socket's.
import java.util.*;   // For the Scanner class.

public class TextSender {

    public static void main (String[] argv)
    {
	try {
	    // Open a socket to the server: rabbit.seas.gwu.edu, port 9003.  
	    Socket soc = new Socket ("rabbit.cs.gwu.edu", 9003);

 	    // To test on same machine: Socket soc = new Socket ("localhost", 9003);
	    // Note: server must be fired up first!  

	    InetAddress remoteMachine = soc.getInetAddress();
	    System.out.println ("Attempting connection to " + remoteMachine);
      
	    // Now create the output stream and wrap a PrintWriter around it.
	    OutputStream outStream = soc.getOutputStream ();
	    PrintWriter pw = new PrintWriter (outStream);

            // Read text from the screen:
	    Scanner scanner = new Scanner (System.in);
	    System.out.print ("Enter text: ");
	    while (scanner.hasNext()) {
                // Extract string and send it on the socket.
		String line = scanner.next();
		pw.println (line);
                // Note: must flush() to actually cause line to be sent.
		pw.flush();
                // Repeat.
		System.out.print ("Enter text: ");
	    }
	}
	catch (IOException e) { 
	    System.out.println (e); 
	}
    }

}

And now the sender: (source file)

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

public class TextReceiver {

    public static void main (String[] argv)
    {
	try {
	    // Create a listening service for connections at the designated port number.
	    ServerSocket srv = new ServerSocket (9003);

	    // When a connection is made, get the socket.  
	    // The method accept() blocks until then.  
	    System.out.println ("Server: waiting for a connection ... ");
	    Socket soc = srv.accept ();

	    // At this stage, the connection will have been made.  
	    InetAddress remoteMachine = soc.getInetAddress();
	    System.out.println ("Accepted a connection from " + remoteMachine);

	    // We are going to listen, so get an InputStream and wrap a line-reader around it.
	    InputStream in_stream = soc.getInputStream ();      
	    LineNumberReader lnr = new LineNumberReader (new InputStreamReader (in_stream));

	    String line = lnr.readLine ();
	    while (line != null) {
		System.out.println ("Received: " + line);
                // Repeat.
		line = lnr.readLine();
	    }

	}
	catch (IOException e) { 
	    System.out.println (e); 
	}

    }

}

In-Class Exercise 1: Download TextSender.java to hobbes, change the port number to your assigned port number, and compile. Likewise download TextReceiver.java to your rabbit.cs.gwu.edu account, change the port number in the code, then compile. First fire up TextReceiver, then TextSender.

Server vs. client:

In-Class Exercise 2: Change the sender into a "server". That is, create SenderAsServer.java on rabbit.cs.gwu.edu so that the sender (one who prompts for text and sends it) is written as a server that opens a ServerSocket. Now write ReceiverAsClient.java on hobbes, a program that opens a connection to the server, but will actually receive text and display it.


Handling multiple connections

In-Class Exercise 3: Go back to Exercise 1 and run a single TextReceiver (on rabbit.cs.gwu.edu). Now fire up two TextSender's (on hobbes) and try to communicate with the TextReceiver. What do you notice?

We will modify the receiver to handle multiple connections:

Here's the modified receiver: (source file)
import java.io.*;
import java.net.*;
import java.util.*;

public class MultiTextReceiver {

    public static void main (String[] argv)
    {
	try {
	    // Create a listening service for connections at the designated port number.
	    ServerSocket srv = new ServerSocket (9003);
	    
	    int numConnections = 0;

	    while (true) {
		// Wait for a connection to come in.
		System.out.println ("Server: waiting for a connection ...");
		Socket soc = srv.accept ();

		// At this stage, the connection will have been made.  
		InetAddress remoteMachine = soc.getInetAddress();
		System.out.println ("Accepted a connection from " + remoteMachine);

		// We are going to listen, so get an InputStream  
		InputStream inStream = soc.getInputStream ();      
		LineNumberReader lnr = new LineNumberReader (new InputStreamReader (inStream));
		numConnections ++;

                // Create an instance of a object that handles this connection in a separate thread.
		LineReaderObject lineReader = new LineReaderObject (lnr, numConnections);
		System.out.println ("Server: created connection ID=" + numConnections);

                // Start the thread:
		lineReader.start();

	    } //end-while

	}
	catch (IOException e) { 
	    System.out.println (e); 
	}
    }

}


class LineReaderObject extends Thread {

    LineNumberReader lnr;
    int ID;

    public LineReaderObject (LineNumberReader lnr, int ID)
    {
	this.lnr = lnr;
	this.ID = ID;
    }


    // Override the run() method in Thread. This is what is called by the
    // thread once it starts.

    public void run ()
    {
        // readLine() needs a try-catch.
	try {
	    String line = lnr.readLine ();
	    while (line != null) {
		System.out.println ("[I# " + ID + "] Received: " + line);
		line = lnr.readLine();
	    }
	}
	catch (IOException e) {
	    System.out.println (e);
	}
    }

}


Talking to a webserver

We will use the HTTP protocol to fetch a page from a webserver:

Here's an example: (source file)
import java.net.*;
import java.io.*;

public class WebClient {

    public static void main (String[] argv)
    {
        try {
            // Open the connection.
            Socket soc = new Socket ("search.yahoo.com", 80);
            InetAddress remote_machine = soc.getInetAddress();
            System.out.println ("Connected to " + remote_machine);
      
            // Now create the output and input streams
            OutputStream outStream = soc.getOutputStream ();
            PrintWriter pw = new PrintWriter (outStream);
            InputStream inStream = soc.getInputStream();
            LineNumberReader lnr = new LineNumberReader (new InputStreamReader (inStream));
            
            // Make the query.
            pw.print ("GET /bin/search?p=java\n\n");
            pw.flush ();
            
            // Get the results.
            String s = lnr.readLine ();
            while (s != null) {
                System.out.println (s);
                s = lnr.readLine ();
            }

            // Close streams before quitting.
            pw.close ();
            lnr.close ();
            soc.close ();
        }
        catch (IOException e) { 
            System.out.println (e); 
        }
    }
    
}

In-Class Exercise 4: Modify WebClient.java to fetch the index.html page that your webserver delivers on rabbit.cs.gwu.edu. Remember to fire up your webserver first.