Generally, the two socket classes are used to implement both clients and servers , while the ServerSocket class is used to implement servers.
A previous lesson illustrated how to use the Socket class to implement several different types of clients. All of them were relatively simple, and we learned that the difficulty in socket programming derives from the requirements to implement the application protocol and not from the sockets themselves.
In this lesson, we will develop a considerably more substantive program. This program will be a TCP/IP server, implemented using Socket and ServerSocket, that can support both the echo port protocol and part of the HTTP protocol.
In addition, this program will illustrate how to implement a custom security manager for a Java application.
We will defer discussion of the DatagramSocket class until a subsequent lesson.
Socket programming provides a low-level mechanism by which you can connect two computers for the exchange of data. One of those is considered to be the client and the other is considered to be the server.
The client initiates a connection with a server. Servers wait for a clients to initiate connections.
Socket programming makes it possible for you to cause data to flow in a full-duplex mode between a client and a server.
If you use this program for any purpose, you are using it at your own risk.
If you use this program, you should tighten the security manager to the degree needed by your particular situation. You can tighten the security manager by removing the overridden methods that begin with the word check (such as checkAccept) in the class named ServerSecurityManager.
This program implements two different servers operating on two different ports on the same computer running the same program.
One of the servers is an "echo" server that implemented by using a thread object to monitor port 7. This server echoes the string that it receives from a client. Port 7 is the standard echo port.
The other server is an abbreviated HTTP server implemented by using a thread object to monitor port 80. Port 80 is the standard HTTP port. This server has the ability to respond to a GET command from a client and deliver a specified file as a stream of bytes.
Two different servers were implemented on two different ports in this program to illustrate the manner in which threads can be used to service multiple ports within the same program.
A custom security manager is implemented which attempts to prevent the server from delivering any files other than those in the current directory or in a subdirectory of the current directory. The current directory is the directory from which the server program was started.
Otherwise, the security manager is wide open and doesn't enforce any security at all.
Please DO NOT install this server on your network and leave it unattended because client computers could then connect and have broad access to your computer.
This program was tested using JDK 1.1.3 under Win95.
You must be logged onto an appropriate network for this program to run properly. Otherwise, it will throw an exception of type UnknownHostException.
To test this program on a Win95 system, simply start the program as a normal Java application prior to starting the client program being used to test the program (or before causing the client program to attempt to contact the server).
The HTTP portion of this program can be tested under Win95 using an ordinary browser by constructing a URL using the server name localhost and entering that URL in the browser's Location field. Your browser should connect to this program and attempt to download the files that you specify in the URL.
The HTTP portion of the program can also be tested using the client program named Sockets06 which was designed specifically for testing the security manager installed in this program. A listing of Sockets06 is provided near the end of this lesson.
You can also test the security manager portion of this program using an ordinary browser by specifying illegal file names in the URL.
The echo portion of this program can be tested using the client program named Sockets05 which was designed specifically for testing this program. A listing of this program is also provided near the end of this lesson.
I assume that the same, or similar test procedures can also be used on other platforms, but since I don't have access to other platforms, I have no way to verify that assumption.
The main() method of the controlling class for this program contains three significant statements as shown below.
The first statement establishes a custom security manager for the program. I will have more to say about the security manager later.
The second statement instantiates a server object that monitors port 80. This server object implements part of the HTTP protocol and delivers specified files to web browsers.
The third statement instantiates a server object that monitors port 7. This server object functions as an echo server, echoing strings received from TCP/IP clients.
public class Server01{ public static void main(String[] args){ System.setSecurityManager(new ServerSecurityManager()); HttpServer httpServerThread = new HttpServer(); EchoServer echoServerThread = new EchoServer(); }//end main }//end class Server01 |
When you create a security manager for an application, the code in your application is prohibited from doing just about everything. The application has no privileges at all, and you as the designer of the custom security manager, must decide what privileges it should have and arrange for those privileges to be provided.
This is a very tedious and complex process. Although it isn't difficult to make a privilege available once you decide that it should be available, making that decision requires a significant understanding of how privileges relate to operations. Sometimes the relationship between privileges and operations is not obvious at the surface.
To create a custom security manager, you must extend the SecurityManager class. That class contains about 30 methods with names beginning in the word check (such as checkAccept). Those methods control access to various privileges. Each method controls access to a privilege of a type that generally matches the second part of the method name.
The default version of each of these methods is to disallow the privilege that it controls. To make that privilege available, you must override the method, either with an empty method, or with a method that implements a custom version of the privilege.
Deciding which methods to override requires a great deal of knowledge as to the relationship between the privileges controlled by the methods and the operations that the code in your program needs to perform.
In this program, I have overridden all of the check methods except one with an empty method. This causes the privileges associated with each of those methods to be available without restriction.
I overrode the checkRead(String str) method to customize the privilege that it controls rather than to simply make that privilege available without restriction. My intent was to modify this privilege so that the HTTP server could only deliver files from the current directory or from a subdirectory of the current directory. The code that I provided in the overridden version of this method to customize this privilege is shown in the next code fragment.
This is accomplished by confirming that the file specification in the URL is neither based on an absolute path, nor is in the parent directory of the current directory. Recall that the parent directory of the current directory is indicated by two periods (..).
If either of these conditions is true, the code in the overridden method throws a SecurityException.
The following code fragment also contains a small sampling of the other overridden methods of the SecurityManager class. All of these methods are overridden with empty methods. This has the effect of disabling the default version of the methods.
Many methods were omitted from this listing. You will find those methods in the complete listing of the program near the end of this lesson.
class ServerSecurityManager extends SecurityManager{ public void checkRead(String str){ if(new File(str).isAbsolute() || (str.indexOf("..") != -1)) throw new SecurityException( "Access to file: " + str + " denied."); }//end checkRead() public void checkAccept(String s, int i){} public void checkAccess(Thread t){} //many methods were omitted from this listing public void checkWrite(FileDescriptor f){} public void checkWrite(String s){} }//end class ServerSecurityManager |
The second group of classes are those classes needed to create and operate the HTTP server on its own thread.
The echo server is the simpler of the two, so we will discuss it first.
The general operation of both of these servers is as follows. First, each server operates on its own thread, listening to its assigned port for a client to request a connection. While a server is listening for a connection, it is blocked so as to consume minimal resources.
Whenever a client requests a connection on one of the two ports, the server for that port spawns another thread to handle that client's needs and then goes back to listening on its own thread.
The client-support threads are spawned at a lower priority than the server threads to keep them from interfering with the ability of the servers to recognize and respond to the fact that another client might be requesting a connection.
If many different clients request a connection on one of the ports, the server for that port will spawn a new thread to handle each of those clients (within the capabilities of the system). Thus, there could be many different threads in operation at any given time where each thread is serving the needs of a different client.
Let's examine the classes associated with the echo server to see how this is accomplished. As we saw in the main() method earlier in this lesson, the echo server is implemented as on object of the EchoServer class. This class extends Thread and is used to instantiate a thread object that monitors port 7 for connection requests from clients.
As shown below, the constructor for this class simply invokes its own start() method to cause the thread to start running.
class EchoServer extends Thread{ EchoServer(){//constructor start(); //start the thread and invoke the run() method }//end constructor |
When you instantiate a ServerSocket object and invoke the accept() method on that object, the method blocks and waits until a client requests a connection on the specified port. When this happens, a Socket object is automatically instantiated and returned by the accept() method.
This Socket object is automatically connected to the Socket being used by the client that requested the connection, and can be used to communicate with the client.
This is very important. Think about it some more.
No data transfer takes place by way of the ServerSocket object. Rather, the accept() method of that object simply blocks and monitors for a connection request from a client on the specified port. When a request is received, a Socket object is automatically instantiated and automatically connected to the Socket through which the client requested the connection. The new Socket object is returned by the accept() method and can be used to communicate with the Socket owned by the client.
So the first thing that we will do in the run() method of our EchoServer class is to instantiate a ServerSocket object tied to port 7.
Then we will enter an infinite loop and invoke the accept() method on that object as the only statement in the loop.
The accept() method will block, consuming few if any resources, until a connection request is received from a client.
When a connection request is received, we will spawn a new thread object of type EchoConnection to deal with that specific client. We will pass the new Socket object as a parameter to the constructor for the EchoConnection object, and the EchoConnection object will be able to use that Socket object to communicate with that client. The communication protocol for the service provided by this port will be incorporated into the run() method of the EchoConnection class.
Recall that the thread on which the EchoServer object is running is in the middle of an infinite loop. Once the new EchoConnection thread is successfully spawned, the EchoServer object will go back to listening for a connection request from another client.
public void run(){//run method of EchoServer class try{ ServerSocket serverSocket = new ServerSocket(7); while(true) new EchoConnection(serverSocket.accept()); }catch(IOException e){System.out.println(e);} }//end run |
This thread knows nothing about servers or clients. All it knows is that it is connected by way of a TCP/IP socket to another socket on another computer (or possibly another process on the same computer).
The constructor for this object receives a Socket object as a parameter and saves it as an instance variable. This is the Socket object that is connected to the Socket object on the client machine.
We need to make certain that the threads monitoring the ports are not prevented from doing their job by the threads servicing the clients, particularly on platforms that don't provide time slicing for threads of equal priority. Therefore, we will reduce the priority of this new thread to a level that is below the priority level of the threads monitoring the ports. That way, the threads monitoring the ports can always preempt the threads servicing clients whenever a new connection request is received from another client.
Once we have saved the Socket object and adjusted the priority, we invoke the start() method to get this thread up and running. As usual, the start() method will invoke the run() method on this thread.
class EchoConnection extends Thread{ Socket socket; EchoConnection(Socket socket){//constructor this.socket = socket;//save the incoming socket setPriority( NORM_PRIORITY-1 ); start();//start this thread and invoke the run method }//end constructor |
We will get input and output streams on the Socket object exactly as we did when programming from the client side. I have removed that code from the following code fragment for brevity. I have also removed the exception handling code for brevity.
The purpose of the server on this port is to receive a string from a client and to echo it exactly as received.
We will read a line of text from the input stream on the Socket object and then print that same line to the output stream on the same Socket object. The incoming line of text comes from the client and the outgoing line of text goes to the client.
Then we close the socket and that satisfies the protocol requirements for this simple echo server thread.
public void run(){ //Code to get input and output streams and exception // handling code removed for brevity. String input = inputStream.readLine(); outputStream.println(input); socket.close(); }//end run method |
Note that this abbreviated HTTP server is designed to respond only to the GET command from the HTTP protocol. Other HTTP commands are ignored and an error message is sent to the client.
Code in main() instantiates an object of type HttpServer. This is a thread object that instantiates a ServerSocket tied to port 80 which is the standard HTTP port.
Except for being tied to port 80, the operation of this server is identical to the operation of the simple echo server up to the point where protocol becomes important.
The accept() method is invoked on the ServerSocket object inside an infinite loop to block and monitor port 80, listening for a connection request from a client. When such a request occurs, the accept() method instantiates and returns a Socket object, already connected to the Socket on the client machine.
This Socket object is passed as a parameter to the constructor of a new thread object of type HttpConnection. I have not shown any of this preliminary code here because it is virtually identical to the corresponding code in the echo server discussed above. You can view it in the complete program listing near the end of this lesson.
The HttpConnection class is used to spawn a new thread that will communicate with the client and implement an abbreviated version of the HTTP protocol.
The constructor for this class is essentially the same as for the echo server. It saves the incoming Socket object, adjusts the priority of the thread downward as explained earlier, and invokes the start() method which in turn invokes the run() method. Since you have seen code like this earlier in this lesson, I did not include it here.
That brings to the run() method where the work of a thread is always done (or at least where it is controlled).
In the interest of brevity, I am going to remove exception handling code from the following fragments. I am also going to remove code that is the same as what you have seen previously and replace that code with comments.
Most of our previous programs on this topic have created input and output streams to move text data across the socket, and this program does the same. I have removed that code from the following fragment and replaced it with a comment.
However, this program also creates and uses an output stream to transmit an array of bytes to the client. We haven't seen that before in this series of lessons, so the following code fragment will begin with the creation of this new type of output stream object.
public void run(){ //Remove exception handling code. //Remove code used to get input and output streams // that are used to handle text data transfers. //Get stream to transmit an array of bytes byteOutput = new DataOutputStream( socket.getOutputStream()); |
String request = inputStream.readLine(); |
We begin the analysis by creating a new StringTokenizer object named stringTokenizer that represents the String object named request. You might need to go back and review the use of StringTokenizer in order to fully understand some of this code.
First we need to confirm that the request is a GET request. We use an if statement to make this test as shown below.
StringTokenizer stringTokenizer = new StringTokenizer(request); if((stringTokenizer.countTokens() >= 2) && stringTokenizer.nextToken().equals("GET")){ |
The following code fragment is executed if the request is a GET request.
Basically what we are trying to do here is to provide a default file name of index.html in the event that the client didn't specify a file name. It is common practice among web servers to try to send a file having that name when you don't specify the name of the file in your request.
First we will eliminate the possibility that the request contains an extra "/" character, and if so, we will strip it off and discard it.
if((request = stringTokenizer.nextToken()). startsWith("/")){ request = request.substring(1); }//end if on startsWith("/") |
if(request.endsWith("/") || request.equals("")){ request = request + "index.html"; } |
We attempt to open a FileInputStream object tied to the specified file name and path. If it doesn't exist, an exception will be thrown at this point and processed in a catch block further down the page.
If the file does exist and can be read, we create a byte array named data whose size equals the number of bytes that can be read from the file. Then we read the file into that array.
FileInputStream fileInputStream = new FileInputStream(request); byte[] data = new byte[fileInputStream.available()]; fileInputStream.read(data); |
byteOutput.write(data); byteOutput.flush(); |
else outputStream.println( "<HTML><BODY><P>400 Bad Request<P></BODY></HTML>"); |
socket.close(); |
Note that for brevity, I have removed the code from these handlers that displays diagnostic information on the server console.
In fact, I have been removing code that displays status information on the server console throughout this discussion. You can view that code in the complete listing of the program that follows shortly.
Two of these event handlers create an HTML page containing an error message and send it to the client.
catch(FileNotFoundException e){ outputStream.println( "<HTML><BODY><P>404 Not Found<P></BODY></HTML>"); try{ socket.close(); }catch(IOException evt){System.out.println(evt);} }//end catch catch(SecurityException e){ outputStream.println( "<HTML><BODY><P>403 Forbidden<P></BODY></HTML>"); outputStream.println(e); try{ socket.close(); }catch(IOException evt){System.out.println(evt);} }//end catch SecurityException catch( IOException e){ System.out.println( "I/O error " + e ); try{ socket.close(); }catch(IOException evt){System.out.println(evt);} }//end catch }//end run method |
The structure of the last one of these exception handlers is a little bothersome. In particular, we need to close the socket inside the exception handler for an IOException. However, the close() method throws an IOException so we have the possibility of throwing an IOException inside a handler of the same type.
I don't know how to force an IOException while a previous IOException is being handled, so I don't have any way to test this handler to see exactly how it will behave.
/*File Server01.java Copyright 1998, R.G.Baldwin This program uses sockets to implement two different servers on an IP network. The program is intended for illustration and experimentation purposes only. If you use this program for any purpose, you use it at your own risk. If you use this program, you should tighten the security manager to the degree needed by your situation. You can tighten the security manager by removing the overridden methods that begin with the word check (such as checkAccept) in the class named ServerSecurityManager. This program implements two different servers. One of the servers is an "echo" server implemented by a thread monitoring port 7. This server simply echoes the string that it receives from a client. Port 7 is the standard echo port. The other server is an abbreviated HTTP server implemented by a thread monitoring port 80. Port 80 is the standard HTTP port. This server has the ability to respond to a GET command from a web browser and serve a file as a stream of bytes. Two different servers were implemented on two different ports to illustrate the manner in which threads can be used in Java to service multiple ports. A custom security manager is implemented which attempts to prevent the server from serving files other than those in the current directory or in a subdirectory of the current directory. Otherwise, the security manager is wide open and doesn't enforce any security at all. DO NOT install this server on your network and leave it unattended because client computers could connect and have broad access to your computer. This program was tested using JDK 1.1.3 under Win95. The HTTP portion of this program can be tested using an ordinary browser with the server name localhost. It can also be tested using the program named Sockets06 which was designed specifically for testing the security manager installed in this program. However, you can also test the security manager using an ordinary browser. The echo portion of this program can be tested using the program named Sockets05 which was designed specifically for testing this program. **********************************************************/ import java.net.*; import java.io.*; import java.util.*; public class Server01{ public static void main(String[] args){ //Instantiate a new custom security manager. System.setSecurityManager(new ServerSecurityManager()); //Instantiate a server object to listen on port 80 HttpServer httpServerThread = new HttpServer(); //Instantiate a server object to listen on port 7 EchoServer echoServerThread = new EchoServer(); }//end main }//end class Server01 //=======================================================// //=======================================================// //This class is used to instantiate a security manager // that confirms that files can be downloaded only from // the current directory or a subdirectory of that // directory. Note that other than checking for file // downloading, this is a wide open security manager. DO // NOT install it on your network without considering the // need to implement tighter security features. This // security manager class was tested using JDK 1.1.3 // under Win95. class ServerSecurityManager extends SecurityManager{ //This overridden method attempts to allow the server // to deliver files only from the current directory or // from a subdirectory of that directory. public void checkRead(String str){ if(new File(str).isAbsolute() || (str.indexOf("..") != -1)) throw new SecurityException( "Access to file: " + str + " denied."); }//end checkRead() //The following list of overridden methods causes the // security manager to be wide open and eliminates all // security checks other than the one provided by the // previous overridden method. public void checkAccept(String s, int i){} public void checkAccess(Thread t){} public void checkAccess(ThreadGroup g){} public void checkAwtEventQueueAccess(){} public void checkConnect(String s, int i){} public void checkConnect(String s, int i, Object o){} public void checkCreateClassLoader(){} public void checkDelete(String s){} public void checkExec(String s){} public void checkExit(int i){} public void checkLink(String s){} public void checkListen(int i){} public void checkMemberAccess(Class c, int i){} public void checkMulticast(InetAddress a){} public void checkMulticast(InetAddress a, byte b){} public void checkPackageAccess(String s){} public void checkPackageDefinition(String s){} public void checkPrintJobAccess(){} public void checkPropertiesAccess(){} public void checkPropertyAccess(String s){} public void checkRead(FileDescriptor f){} //public void checkRead(String s){}//overridden above public void checkRead(String s, Object o){} public void checkSecurityAccess(String s){} public void checkSetFactory(){} public void checkSystemClipboardAccess(){} public boolean checkTopLevelWindow(Object o) {return true;} public void checkWrite(FileDescriptor f){} public void checkWrite(String s){} }//end class ServerSecurityManager //=======================================================// //=======================================================// //This class is used to instantiate a server thread that // listens on port 7 which is the echo port. class EchoServer extends Thread{ EchoServer(){//constructor start(); //start the thread and invoke the run() method }//end constructor //-----------------------------------------------------// public void run(){ try{ //Instantiate a serverSocket on port 7 (echo port) ServerSocket serverSocket = new ServerSocket(7); System.out.println("Server Listening on port 7"); //Loop and listen to port 7. If a call is // received, spawn an EchoConnection thread to // deal with it. while(true) //This statement blocks on the accept() method // and returns a socket if a call is received. // The socket is passed as a parameter to the // new thread that is spawned. new EchoConnection(serverSocket.accept()); }catch(IOException e){System.out.println(e);} }//end run }//end class EchoServer //=======================================================// //This class is used to spawn a thread to deal with a // call that is received on port 7 which is the echo // port. class EchoConnection extends Thread{ Socket socket; EchoConnection(Socket socket){//constructor System.out.println("Received a call on port 7"); this.socket = socket; //Operate at a priority that is below the threads // listening on the ports. setPriority( NORM_PRIORITY-1 ); start();//start this thread and invoke the run method }//end constructor //-----------------------------------------------------// public void run(){ System.out.println("Running thread for port 7"); BufferedReader inputStream = null; PrintWriter outputStream = null; try{ //Get an input stream from the socket inputStream = new BufferedReader(new InputStreamReader( socket.getInputStream())); //Get an output stream to the socket. Note // that this stream is supposed to autoflush. outputStream = new PrintWriter(new OutputStreamWriter( socket.getOutputStream()),true); //Get input from the browser and echo it to // the browser String input = inputStream.readLine(); outputStream.println(input); System.out.println("Got Input: "+ input); socket.close(); System.out.println("Socket closed"); }//end catch( IOException e) {System.out.println( "I/O error " + e );} }//end run method }//end class EchoConnection //=======================================================// //=======================================================// //This class is used to instantiate a server thread that // listens on port 80 which is the http port. class HttpServer extends Thread{ HttpServer(){//constructor start(); //start the thread and invoke the run() method }//end constructor //-----------------------------------------------------// public void run(){ try{ //Instantiate a serverSocket on port 80 (http port) ServerSocket serverSocket = new ServerSocket(80); System.out.println("Server Listening on port 80"); //Loop and listen to port 80. If a call is // received, spawn an HttpConnection thread to // deal with it. while(true) //This statement blocks on the accept() method // and returns a socket if a call is received. // The socket is passed as a parameter to the // new thread that is spawned. new HttpConnection(serverSocket.accept()); }catch(IOException e){System.out.println(e);} }//end run }//end class HttpServer //=======================================================// //This class is used to spawn a thread to deal with a // call that is received on port 80 which is the http // port. class HttpConnection extends Thread{ Socket socket; BufferedReader inputStream = null; PrintWriter outputStream = null; DataOutputStream byteOutput = null; HttpConnection(Socket socket){//constructor System.out.println("Received a call on port 80"); this.socket = socket; //Operate at a priority that is below the threads // listening on the ports. setPriority( NORM_PRIORITY-1 ); start();//start this thread and invoke the run method }//end constructor //-----------------------------------------------------// public void run(){ System.out.println("Running thread for port 80"); try{ //Get an input stream from the socket inputStream = new BufferedReader(new InputStreamReader( socket.getInputStream())); //Get an output stream to the socket to use for // sending text strings. Note that this stream // will autoflush. outputStream = new PrintWriter(new OutputStreamWriter( socket.getOutputStream()),true); //Get an output stream to the socket to use for // sending an array of byte data to a client. byteOutput = new DataOutputStream( socket.getOutputStream()); //Get request from the browser String request = inputStream.readLine(); System.out.println("Got Request: "+ request); //Now analyze and attempt to respond to the request. // Note that this program supports only the GET // request. Any other request will be ignored. StringTokenizer stringTokenizer = new StringTokenizer(request); if((stringTokenizer.countTokens() >= 2) && stringTokenizer.nextToken().equals("GET")){ System.out.println("First token is GET"); if((request = stringTokenizer.nextToken()). startsWith("/")){ System.out.println( "Next token starts with /, strip it off"); request = request.substring(1); }//end if on startsWith("/") if(request.endsWith("/") || request.equals("")){ System.out.println("Request endsWith / or " + "blank, append index.html"); request = request + "index.html"; System.out.println( "Modified request: " + request); }//end if on / or "" System.out.println("Try to read: " + request); FileInputStream fileInputStream = new FileInputStream(request); //Instantiate a byte array whose size is equal to // the number of bytes that can be read from this // fileInputStream without blocking. Then read the // file into the byte array. byte[] data = new byte[fileInputStream.available()]; fileInputStream.read(data); //Send the bytes in the array to the client. byteOutput.write(data); byteOutput.flush(); }//end if stringTokenizer.countTokens... else //This happens when the request is not GET outputStream.println("<HTML><BODY><P>400 Bad " + "Request<P></BODY></HTML>"); socket.close(); System.out.println("Socket closed"); }//end catch(FileNotFoundException e){ outputStream.println( "<HTML><BODY><P>404 Not Found<P></BODY></HTML>"); try{ socket.close(); System.out.println("Socket closed"); }catch(IOException evt){System.out.println(evt);} }//end catch catch(SecurityException e){ System.out.println(e); e.printStackTrace(); outputStream.println( "<HTML><BODY><P>403 Forbidden<P></BODY></HTML>"); outputStream.println(e); try{ socket.close(); System.out.println("Socket closed"); }catch(IOException evt){System.out.println(evt);} }//end catch SecurityException catch( IOException e){ System.out.println( "I/O error " + e ); try{ socket.close(); System.out.println("Socket closed"); }catch(IOException evt){System.out.println(evt);} }//end catch }//end run method }//end class HttpConnection //=======================================================// |
/*File Sockets05.java Copyright 1998, R.G.Baldwin Revised 01/20/98 This program is just like Sockets03 except that it opens a socket to localhost. It is used to test the echo portion of the server in the program named Server01. This program performs a simple echo test with a server by sending a line of text to the echo port, port 7. You must be logged onto an appropriate network for this program to run properly. Otherwise, it will throw an exception of type UnknownHostException. Most of the program is enclosed in a try/catch block to deal with possible exceptions. The program begins by instantiating a String object containing the name of an echo server that you are using to test the program. This is followed by declaration and initialization of an int variable containing the standard echo port number. The standard echo port is number 7. Than the program gets a socket connection to port 7 on the echo server. Then the program gets input and output streams from the socket and wraps them in the new reader classes. Once the input and output streams are ready to use, the sends a line of text to the echo port on the server. The echo server sends the same line of text back to the client. Then the program reads the line of text that is received and displays it. Then the program closes the socket and terminates. This program was tested using JDK 1.1.3 under Win95. The output from this program is: This is an echo test **********************************************************/ import java.net.*; import java.io.*; import java.util.*; class Sockets05{ public static void main(String[] args){ String server = "localhost"; int port = 7; //echo port try{ //Get a socket, connected to the specified server // on the specified port. Socket socket = new Socket(server,port); //Get an input stream from the socket BufferedReader inputStream = new BufferedReader(new InputStreamReader( socket.getInputStream())); //Get an output stream to the socket. Note // that this stream will autoflush. PrintWriter outputStream = new PrintWriter(new OutputStreamWriter( socket.getOutputStream()),true); //Send line of text to the server outputStream.println("This is an echo test"); //Get echoed line back from server and display it System.out.println(inputStream.readLine()); //Close the socket socket.close(); }//end try catch(UnknownHostException e){ System.out.println(e); System.out.println( "Must be online to run properly."); }//end catch UnknownHostException catch(IOException e){System.out.println(e);} }//end main }//end class Sockets05 //=======================================================// |
/*File Sockets06.java Copyright 1998, R.G.Baldwin Revised 01/20/98 The sole purpose of this program is to test the custom security manager implemented in the program named Server01. This program is the same as Sockets01 except that it connects to localhost and attempts to download a file protected by the security manager in the program named Server01. This program is a simple http client (web browser) implemented using sockets. The program implements just enough of the http protocol to make it capable of getting an html page from an http server (assuming that access to the requested file is allowed by the security manager on the server). You must be logged onto an appropriate network for this program to run properly. Otherwise, it will throw an exception of type UnknownHostException. Most of the program is enclosed in a try/catch block to deal with possible exceptions. The program begins by defining the name of a server and the number of the http port on that server. The standard port number for http servers is 80. Then the program opens a socket to the specified server on the specified port. Then it uses the new BufferedReader class along with the new InputStreamReader class to open an input stream from the socket. These classes are wrapped around an input stream provided by the Socket class. Then it uses the new PrintWriter class along with the new OutputStreamWriter class to open an output stream to the socket. These classes are also wrapped around an output stream provided by the Socket class. The output stream will autoflush, which is critical. If the output stream isn't flushed, the server will not respond (presumably it doesn't receive all of the output data until the stream is flushed). Then the program, acting as an http client, sends a GET command to the server specifying a particular path and file name. Two versions of this statement are included. One statement attempts to get a file using an absolute pathname. The other statement attempts to get a file from the parent directory. Both of these two possibilities are prohibited by the custom security manager in the program named Server01. This causes the server to attempt to fetch the specified file and send it to the client. Since access to these files is not allowed, a SecurityException is thrown in Server01 which causes error messages to be sent to the client. Then this program reads lines from the input stream and displays them on the standard output device. In this case, they will be error messages. When there are no more lines to be read, a null is received. This causes the client to exit the input loop and to close the socket. This program was tested using JDK 1.1.3 under Win95. **********************************************************/ import java.net.*; import java.io.*; class Sockets06{ public static void main(String[] args){ String server = "localhost";//server name int port = 80; //http port try{ //Get a socket, connected to the specified server // on the specified port. Socket socket = new Socket(server,port); //Get an input stream from the socket BufferedReader inputStream = new BufferedReader(new InputStreamReader( socket.getInputStream())); //Get an output stream to the socket. Note // that this stream will autoflush. PrintWriter outputStream = new PrintWriter(new OutputStreamWriter( socket.getOutputStream()),true); //Send a GET command to the server. Either of the // following statements will cause the program named // Server01 to throw a SecurityException. //Test ability to get file from parent directory // outputStream.println("GET ../baldwin/Test01.html"); //Test ability to get file using absolute pathname outputStream.println("GET C:/index.html"); //Declare a String to read lines into. String line = null; //Loop reading and displaying lines until null // is received. while((line = inputStream.readLine()) != null) System.out.println(line); //Close the socket socket.close(); }//end try catch(UnknownHostException e){ System.out.println(e); System.out.println( "Must be online to run properly."); }//end catch UnknownHostException catch(IOException e){System.out.println(e);} }//end main }//end class Sockets06 //=======================================================// |
-end-