Sockets and Multithreading


For this lecture, we will focus on two of the primary operations on a Thread:

In order for a process to run as a separate thread, it needs to do one of the following:

Subclass from Thread

	public class Fibonacci extends Thread {
		private long numDigits;

		public Fibonacci(long numDigits) {
			this.numDigits = numDigits;
		}

		public void run() {
			int prevNbr = 0;
			int currNbr = 1;
			int nextNbr = 0;

			System.out.print("" + prevNbr);

			for ( int i=0; i<numDigits; i++ ) {
				System.out.print(", " + currNbr);
				nextNbr = prevNbr + currNbr;
				prevNbr = currNbr;
				currNbr = nextNbr;
			}

			System.out.println("");
		}
	}
The following code would then create a thread and start it running:
	Fibonacci f = new Fibonacci(10);
	f.start();
Implement the Runnable interface
	public class Fibonacci implements Runnable {
		private long numDigits;

		public Fibonacci(long numDigits) {
			this.numDigits = numDigits;
		}

		public void run() {
			int prevNbr = 0;
			int currNbr = 1;
			int nextNbr = 0;

			System.out.print("" + prevNbr);

			for ( int i=0; i<numDigits; i++ ) {
				System.out.print(", " + currNbr);
				nextNbr = prevNbr + currNbr;
				prevNbr = currNbr;
				currNbr = nextNbr;
			}

			System.out.println("");
		}
The following code would then create a thread and start it running:
	Fibonacci f = new Fibonacci(143);
	new Thread(f).start();
One additional consideration with Threads is synchronization. You may have two or more threads that need to share the same object. To prevent them from stepping on each other, you need to synchronize either the method:
	public synchronized void SomeMethod() {

			or a code block with an object:

	synchronized (object) {
		// code
	}
Sockets

A socket is simply an endpoint for communication between two machines. The simplest socket is one that uses the ServerSocket and Socket classes to pass information as an I/O stream.

This is also an ideal place for utilizing threads. Ideally, you want your socket server to be available all the time for multiple requests. So, the server would receive and accept a connection, then pass that connection on to a separate thread which processes the request.

Let's create a set of classes that will contain a client, server, and processor. The client requests a connection to the server, then passes the request for a file to the server. The server hands off the connection and request to a new processor thread. The processor thread opens the requested file and passes the contents back to the client. This is similar to how the Internet works.

The required packages are:

	import java.net.*;
	import java.io.*;
Let's look at what we need for the socket request processor first. In order to run as a thread, it has to implement the Runnable interface:
		public class SocketProcessor implements Runnable {
We'll create a constructor method that takes the Socket connection as an argument:
	public SocketProcessor(Socket connected) {
Because it implements Runnable, we must have the following method:
	public void run() {
In the run method, we'll get the input and output streams of the Socket:
	BufferedReader reader = new BufferedReader(new InputStreamReader(connected.getInputStream()));
	BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connected.getOutputStream()));
We read the filename from the input stream, then create another BufferedReader to read the contents of the file into a string and passes it to the output stream.

Once that's finished we call the close() method on the connection.

The server class will run as an application, so we need the main method:

	public static void main(String args[]){
In the main method, we need to start a ServerSocket that listens on a particular port:
	ServerSocket s = new ServerSocket(7777);
The port number is not relevant, as long as it's one not in use.

The next step is to accept a connection request. However, we don't want it to accept one connection then end, so we enclose the process in an endless loop:

	while (true) {
		Socket connected = s.accept();
		SocketProcessor sp = new SocketProcessor(connected);
		new Thread(sp).start();
	}
In this loop, we accept the request, create a new processor thread, and start the thread.

For the client, we first need to request a connection to the server:

	Socket client = new Socket("localhost", 7777);
Once this is done, we need to get the input and output streams of the Socket:
	BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
	BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
For the output stream, we write to it the name of the file we want. Note that the write method does not pass the new line (carriage return, line feed). The processor is doing a readLine, and only knows the end of the line when it receives the new line. So, we need to write the new line using the newLine() method of the BufferedWriter. We also need to flush the buffer.

Once that's done, we can read from the input stream the data coming to us from the processor.

To run this, start the socket server first, then start the socket client.