Reading and writing to a socket a slightly less simple server

22 Apr

Reading and writing to a socket (a slightly less simple server)

The server we looked at in the previous example was very simple. It suffered from the fact that the server contained a loop that would never end, forcing you to shut the window down to kill the program. Let’s look at a similar example in which the server now examines client requests to look for a command to shut down. The program below creates a ServerSocket object binding to port 80. It uses that ServerSocket object to listen for client requests for connection to port 80. When it sees one, it creates a separate Socket object, on a different port, to the client. Buffered IO streams are created to read and write from the socket. Each time the client requests a connection to the server, a count is incremented and that count is sent back to the client in the form of text that will be viewed by a browser as a web page. The text is passed through the streams via HTTP protocol. This is an example of data encapsulation: HTML text is being passed to a web browser via HTTP. The web page has HTML FORM elements in it that can be used by the browser to send back a command to either increment the counter, or quit. Client requests are examined to see whether or not they contain the QUIT command. If so, the streams and socket are closed and the server is shut down.

Listing 3-17: HttpImporvedServer.java

import java.util.*;
import java.io.*;
import java.net.*;
public class HttpImprovedServer {
public static void main(String[] args) {
int port = 80;
int count=0;
boolean serverFlag = true;
try {
ServerSocket srv = new ServerSocket(port);
while (serverFlag) {
Socket mySocket = srv.accept();
BufferedWriter serverResponse = new BufferedWriter(
new  OutputStreamWriter(mySocket.getOutputStream()));
BufferedReader clientRequest = new BufferedReader(
new  InputStreamReader(mySocket.getInputStream()));
String str;
str= clientRequest.readLine();
System.out.println(str);
if (str.startsWith(“GET /?QUIT”)) {
serverFlag = false;
sayGoodbye(serverResponse,  count);
} else {
count++;
writePage(serverResponse,  count);
}
clientRequest.close();
mySocket.close();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println(“Problem with main”);
}
}
public static void writePage(BufferedWriter wr, int df) {
String str=String.valueOf(df);
try {
wr.write(“HTTP/1.0 200 OK\n”);
wr.write(“Content-type:  text/html\n\n”);
wr.write(“<HEAD>\n”);
wr.write(“<TITLE>This is a counting test web page</TITLE>\n”);
wr.write(“<H3><CENTER>An HTTP counter</CENTER></H3>\n”);
wr.write(“</HEAD>\n”);
wr.write(“<BODY><CENTER>\n”);
wr.write(“Push the Button to Update the Count\n”);
wr.write(“<FORM>”);
wr.write(“<INPUT TYPE=SUBMIT NAME=’Increment’ VALUE=’Increment’>”);
wr.write(“<INPUT TYPE=SUBMIT NAME=’QUIT’ VALUE=’QUIT’>”);
wr.write(“</FORM>”);
wr.write(“The current count = “ + str);
wr.write(“</CENTER></BODY>\n”);
wr.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println(“There is an IOException in writePage”);
}
}
public static void sayGoodbye(BufferedWriter wr, int df) {
String str=String.valueOf(df);
try {
wr.write(“HTTP/1.0 200 OK\n”);
wr.write(“Content-type:  text/html\n\n”);
wr.write(“<HEAD>\n”);
wr.write(“<TITLE>Goodbye!</TITLE>\n”);
wr.write(“<H3><CENTER>Goodbye</CENTER></H3>\n”);
wr.write(“</HEAD>\n”);
wr.write(“<BODY><CENTER>\n”);
wr.write(“The final count = “ + str);
wr.write(“</CENTER></BODY>\n”);
wr.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println(“There is an IOException in sayGoodbye”);
}
}
}

The program starts with the usual import statements to access the necessary libraries and the class declaration. The main method begins by declaring a port variable, an integer count variable, and a boolean flag. The flag, serverFlag, is used to identify whether or not the program should continue to look for client requests in a loop. A ServerSocket object binding to port 80 is created that will allow it to wait for client connection requests to port 80 via the accept() method.

import java.util.*;
import java.io.*;
import java.net.*;
public class HttpSocketServer {
public static void main(String[] args) {
int port = 80;
int count=0;
boolean serverFlag = true;
try {
ServerSocket srv = new ServerSocket(port);

A loop based on our flag, serverFlag, begins. We start by waiting for the client connection request to port 80. When it occurs, a Socket object is created on a different port, to provide communication to the client. IO streams are created for reading and writing to this socket, clientRequest and serverResponse. Again, we used BufferedWriter and Bufferedreader objects as our streams.

while (serverFlag) {
Socket mySocket = srv.accept();
BufferedWriter serverResponse = new BufferedWriter(
new  OutputStreamWriter(mySocket.getOutputStream()));
BufferedReader clientRequest = new BufferedReader(
new  InputStreamReader(mySocket.getInputStream()));

A String object is declared and it is used to hold the text that the client is sending to the server via the socket. It’s read from the socket via the readLine() method. The string is printed to the screen in which the server was invoked. It is then scanned for the text that would result if the QUIT form element on the web page being served by our server has been depressed. If it finds it, we set our flag so that our continuous loop is stopped and the server is shutdown. A goodbye/final count web page is served to the client before the shutdown. If the input from the client does not indicate a QUIT, it increments our count variable and serves the web page right back to the client with the revised count. All of the web page serving is done via one of two methods. Once the client has been served either a goodbye page or a revised count page, the clientRequest stream and the mySocket  Socket object is closed.

String str;
str= clientRequest.readLine();
System.out.println(str);
if (str.startsWith(“GET /?QUIT”)) {
serverFlag = false;
sayGoodbye(serverResponse,  count);
} else {
count++;
writePage(serverResponse,  count);
}
clientRequest.close();
mySocket.close();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println(“Problem with main”);
}
}

This method, writePage(), writes an HTML web page using the HTTP protocol to the client via the socket. It takes a BufferedWriter and an integer as arguments. The first two lines written represent the HTTP protocol sever response header. The rest is HTML text. The web page is actually a very simple page that features a count, representing the number of times the page has been served The HTML also contains a form having two buttons. One button is pressed if you want to increment the count, the other is pressed if you want to shut down the server. After writing the text to the socket, we catch any IOException that may have occurred. All writing to the socket is done via the BufferedWriter.write() method.

public static void writePage(BufferedWriter wr, int df) {
String str=String.valueOf(df);
try {
wr.write(“HTTP/1.0 200 OK\n”);
wr.write(“Content-type:  text/html\n\n”);
wr.write(“<HEAD>\n”);
wr.write(“<TITLE>This is a counting test web page</TITLE>\n”);
wr.write(“<H3><CENTER>An HTTP counter</CENTER></H3>\n”);
wr.write(“</HEAD>\n”);
wr.write(“<BODY><CENTER>\n”);
wr.write(“Push the Button to Update the Count\n”);
wr.write(“<FORM>”);
wr.write(“<INPUT TYPE=SUBMIT NAME=’Increment’ VALUE=’Increment’>”);
wr.write(“<INPUT TYPE=SUBMIT NAME=’QUIT’ VALUE=’QUIT’>”);
wr.write(“</FORM>”);
wr.write(“The current count = “ + str);
wr.write(“</CENTER></BODY>\n”);
wr.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println(“There is an IOException in writePage”);
}
}

This method, sayGoodBye() also writes an HTML web page using the HTTP protocol to the client via the socket. Like the writePage() method, it takes a BufferedWriter and an integer as arguments. The first two lines written represent the HTTP protocol server response header. The rest is HTML text. This web page prints the final count and some text saying “goodbye.” After writing the text to the socket, we catch any IOException that may have occurred. All writing to the socket is done via the BufferedWriter.write() method.

public static void sayGoodbye(BufferedWriter wr, int df) {
String str=String.valueOf(df);
try {
wr.write(“HTTP/1.0 200 OK\n”);
wr.write(“Content-type:  text/html\n\n”);
wr.write(“<HEAD>\n”);
wr.write(“<TITLE>Goodbye!</TITLE>\n”);
wr.write(“<H3><CENTER>Goodbye</CENTER></H3>\n”);
wr.write(“</HEAD>\n”);
wr.write(“<BODY><CENTER>\n”);
wr.write(“The final count = “ + str);
wr.write(“</CENTER></BODY>\n”);
wr.flush();
} catch (IOException e) {
e.printStackTrace();
System.out.println(“There is an IOException in sayGoodbye”);
}
}

To try this program out, invoke the HttpImprovedServer program from the command line and then open up a web browser and type in the URL http://127.0.0.1/ Both the command line window and the browser should respond as shown below. The IP address 127.0.0.1 is what is known as the loop-back address. It refers to the machine you are running on (the localhost). The command line looks like this:

c:\> javac HttpImprovedServer.java
c:\> java HttpImprovedServer
GET / HTTP/1.1
GET /?Increment=Increment HTTP/1.1
GET /?Increment=Increment HTTP/1.1
GET /?Increment=Increment HTTP/1.1
GET /?Increment=Increment HTTP/1.1
GET /?Increment=Increment HTTP/1.1
GET /?Increment=Increment HTTP/1.1
GET /?QUIT=QUIT HTTP/1.1

Random Posts

Comments are closed.