Generally, the two socket classes are used to implement both clients and servers , while the ServerSocket class is only used to implement servers. We will see numerous examples of socket programming in this and subsequent lessons.
This lesson will concentrate on the use of the Socket class. The other two classes will be covered in subsequent lessons.
Socket programming provides a low-level mechanism by which you can connect two computers for the exchange of data. One of those is generally considered to be the client while the other is considered to be the server.
The client initiates a connection with a server. Servers wait for a clients to initiate connections.
The governing protocol will determine what happens after the connection is made. In order for two computers to communicate effectively, they must each implement some mutually acceptable application protocol
Socket programming makes it possible for you to cause data to flow in a full-duplex mode between a client and a server. This data flow can be viewed in almost exactly the same way that we view data flow to and from a disk: as a stream of bytes.
As with most stream data processing, the system is responsible for moving the bytes from the source to the destination. It is the responsibility of the programmer to assign meaning to those bytes.
Assigning meaning takes on a special significance for socket programming. In particular, as mentioned above, it is the responsibility of the programmer to implement a mutually acceptable communication protocol, at the application level, to cause the data to flow in an orderly manner. Some of the bytes are used to implement the protocol, and some of the bytes are used to transfer data.
An application protocol is a set of rules by which the programs in the two computers can carry on a conversation and transfer data in the process.
For example, we will write a program using the SMTP mail protocol to send an email message to someone. We will also write a program that implements a very abbreviated form of the HTTP protocol to download web pages from a server and to display them.
Each of these programs will involve adherence to a fairly simple protocol (at least the part that we implement will be simple).
We will also write a program that obtains the date and time from another computer. In this case, the protocol is about as simple as it can possibly be. In this case, the client will simply make the connection and listen for a string containing the date and time. In this case, the client isn't even required to make a request.
It is easy to use sockets to write code that will cause a stream of bytes to flow in both directions between a client and a server. This is no more difficult than causing a stream of bytes to flow in both directions between memory and a file on a disk.
Getting the bytes to flow is the easy part. Beyond that, you must do all of the programming to implement an application protocol that is understood by both the client and the server. Often that is the more difficult part.
You must be logged onto an appropriate network for this program to run properly. However, it is possible that the network can exist completely within a single computer under some operating systems. (We will learn to cause a single computer to simulate a network under Win95 later.) Otherwise, the program will throw an exception of type UnknownHostException.
The program begins by instantiating a String object containing the name of an echo server that is being used to test the program.
This is followed by the declaration and initialization of an int variable containing the standard echo port number. The standard echo port is port 7.
Than the program gets a socket connection to port 7 on the server.
Following this, the program gets input and output streams from the socket and wraps them in the new Reader and Writer classes. You may want to pay particular attention to this, because as of this writing in January of 1998, it is difficult to find written material that explains how to use the Reader and Writer classes in conjunction with socket programming.
Once the connection is made and the input and output streams are ready to use, the program sends a line of text to the echo port on the specified server.
This causes the server to send the same line of text back to the client.
The program reads the line of text that is received and displays it.
Finally, the program closes the socket and terminates.
This program was tested using JDK 1.1.3 under Win95.
Assuming that you select a server that supports echo processing on port 7, the output from this program should be:
This is an echo test
If you select a server that does not support echo processing on port 7, your output will be different. For example, I tried to run this program on the server identified as "www.whitehouse.net" and the response was something like "connection refused."
This is an interesting result because, as we will see later, that URL does support the daytime port on port 13 that delivers the date and time.
We will begin with the first few lines in the main() method of the controlling class where we declare two local variables that you will need to recognize later.
These variables are used later to specify the server and the
port on the server that we are connecting to.
String server = "www2.austin.cc.tx.us"; int port = 7; //echo port |
The next code fragment is the the key statement in this program insofar as learning new material is concerned.
This statement establishes a connection with the specified port on the specified server by instantiating a new object of type Socket.
Once this object exists, it is possible to use it to communicate with the server on the specified port using the protocol prescribed for the service being delivered on that port.
The constructor for this class throws two different types of exceptions
so you will need to wrap this statement in a try/catch block. The two types
of exceptions are: UnknownHostException and IOException.
Socket socket = new Socket(server,port); |
The only thing remarkable about this code is the fact that it uses the Reader and Writer capabilities of JDK 1.1. Most of the books that I have read are still using deprecated methods from JDK 1.0 in their sample programs for socket programming.
Of the many books that I reviewed on this topic, the only one that I found that had upgraded to the Reader and Writer classes was Java, How to Program, Second Edition, by Deitel and Deitel.
I find the proper use of the I/O stream library to be one of the most difficult, confusing, and tedious aspect of Java programming, and it became even more difficult with the advent of the new classes in JDK 1.1. I was thankful to find information in the Deitel book about how to use these new classes to properly construct the streams needed for socket programming.
Note that the true parameter in the last line will cause the
output stream to flush automatically. Proper flushing is an important aspect
of socket programming.
//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); |
After we we display the echo, we close the socket.
outputStream.println("This is an echo test"); System.out.println(inputStream.readLine()); socket.close(); |
That's really about all there is to socket programming from the client viewpoint.
Beyond this, the programming complexity associated with socket programming is the result of the requirement to implement an application protocol that will successfully communicate with the server.
/*File Sockets03.java Copyright 1998, R.G.Baldwin Revised 01/20/98 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 Sockets03{ public static void main(String[] args){ String server = "www2.austin.cc.tx.us"; 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 Sockets03 //=======================================================// |
This program is even simpler than the previous one, because it isn't necessary to send anything to the server to get the desired result. All that is necessary to cause the server to send the desired information is to make the connection.
This program gets and displays the date and time on the server at "www.whitehouse.net".
It also displays the current date and time in Austin, TX (or wherever the program happens to be run) for comparison.
You must be logged onto an appropriate network for this program to run properly. Otherwise, it will throw an exception of type UnknownHostException.
The program begins by instantiating a String object containing the name of the server being used to test the program.
This is followed by the declaration and initialization of an int variable identifying the standard daytime port. The standard daytime port is port 13.
Than the program gets a socket connection to port 13 on the specified server.
Following this, the program gets an input stream from the socket and wraps it in the new reader classes.
This program doesn't't need an output stream because the client doesn't send anything to the server. Simply connecting is sufficient to trigger the server to send the date and time.
After the connection is made via the socket and the input stream is ready to use, the client reads a line of incoming text. This line of text contains the date and time sent by the server.
The program displays this line of text, and also gets and displays the date and time on the local system using the Date class for comparison.
Then the program closes the socket and terminates.
This program was tested using JDK 1.1.3 under Win95.
The output from this program for one particular run was:
Got socket Current time at www.whitehouse.net: Wed Jan 21 00:31:13 1998 Current time in Austin, TX: Tue Jan 20 23:31:18 CST 1998 |
Note also that there was a five-second difference in the two clocks with the server clock appearing to be slow relative to the client clock.
Prior to running this test, I synchronized the clock in my computer with a Naval Observatory time standard in Washington, D.C. I don't know how much of the five second difference was attributable to transmission time of the data from the server to the client, and how much was due to the fact that one or the other of the clocks wasn't exactly correct.
Therefore, I won't bore you with highlighted code fragments from this program.
/*File Sockets04.java Copyright 1998, R.G.Baldwin Revised 01/20/98 This program gets and displays the date and time on the server at "www.whitehouse.net". It also displays the current date and time in Austin, TX, or wherever the program happens to be run. 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 the server being used to test the program. This is followed by declaration and initialization of an int variable containing the standard daytime port. The standard daytime port is number 13. Than the program gets a socket connection to port 13 on the daytime server. Then the program gets an input stream from the socket and wraps it in the new reader classes. Once the input stream is ready to use, the client reads a line of incoming text. This is the date and time sent by the server. Then the program displays this line of text, and also gets and displays the date and time on the local system using the Date class. Then the program closes the socket and terminates. This program was tested using JDK 1.1.3 under Win95. The output from this program was: Got socket Current time at www.whitehouse.net: Wed Jan 21 00:31:13 1998 Current time in Austin, TX: Tue Jan 20 23:31:18 CST 1998 **********************************************************/ import java.net.*; import java.io.*; import java.util.*; class Sockets04{ public static void main(String[] args){ String server = "www.whitehouse.net"; int port = 13; //daytime port try{ //Get a socket, connected to the specified server // on the specified port. Socket socket = new Socket(server,port); System.out.println("Got socket"); //Get an input stream from the socket BufferedReader inputStream = new BufferedReader(new InputStreamReader( socket.getInputStream())); System.out.println( "Current time at www.whitehouse.net:"); System.out.println(inputStream.readLine()); System.out.println("Current time in Austin, TX:"); System.out.println(new Date()); //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 Sockets04 //=======================================================// |
The program implements just enough of the HTTP protocol to make it capable of getting an HTML page (or any other type of file for that matter) from an HTTP server. Considerably more programming effort would be required to turn it into a useful browser, but such programming should be within the reach of the persons enrolled in Prof. Baldwin's Advanced Java Programming course at ACC
You must be logged onto an appropriate network for this program to run properly. Otherwise, it will throw an exception of type UnknownHostException.
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 port 80.
Then the program opens a socket to the specified server on the specified port.
As in the previous programs, this program creates input and output stream objects for transferring data between the client and the server.
As mentioned earlier, the output stream will autoflush, which is critical. If the output stream isn't flushed, the server will not respond properly (presumably it may not receive all of the 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. The GET command is part of the HTTP application protocol.
This causes the server to attempt to fetch the specified file and send it to the client. If the server is being properly supported on the specific port, it will send something, although that something could be an error message.
The program reads lines of text from the input stream and displays them on the standard output device. Note that even though this may be HTML data, it is displayed as ordinary text. Therefore, if it is HTML, you will see it in raw form including all of the HTML tags.
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.
As of 01/20/98, the output from this program was as follows. This is
a text representation of an HTML file named Test01.html. Note that the
contents of this test file on the server may change over time, so you may
not see exactly the same result if you compile and run this program.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> <HTML> <HEAD>Note that some lines of text were deleted in the interest of brevity. <P>This test file is used to test certain network programming applications.</P> </BODY> </HTML> |
Following this, it instantiates stream objects for input and output using the new Reader and Writer classes. I won't highlight that code here, because it is essentially the same as what you saw in the first program in this lesson.
The HTTP protocol provides several different commands or requests that the client can send to the server. This program implements only the GET command. This is a request by the client to find and download a specified file.
The statement used by the client to request the file named Test01.html from the server is shown below.
Note that the request includes not only the file name, but also the path to that file relative to the directory that the HTTP server software considers to be the pseudo-root. This is probably not the actual root directory on the server computer, but rather is a logical root.
The server software is willing to access and deliver files from directories relative to this pseudo-root.
Note that the request is actually made by printing a line of text on
the stream that is connected to the server.
outputStream.println("GET /baldwin/Test01.html"); |
The next fragment reads that text from the input stream, displays it
on the standard output device, and closes the socket when there is no more
data to be extracted from the input stream.
String line = null; while((line = inputStream.readLine()) != null) System.out.println(line); socket.close(); |
An interesting exercise for the student would be to improve this program to give it additional browser characteristics.
For example, you could review the specifications for HTML and write a display method that would display the data in the style normally associated with HTML pages.
You could wrap the entire program in a Graphical User Interface with a TextArea for display and a TextField for specifying the URL.
You could review the HTTP specifications and implement additional client requests for the HTTP protocol.
Or, you could start with this program and write a "web crawler" program that would begin at some specified URL, downloading files and following links until you either terminate the program after reaching some depth level on links, or fill up your disk with downloaded files.
A safer program for starters would be a web crawler that follows links but doesn't actually save the files that it downloads. It would download each file, parse it to extract the links, and then discard everything but the links.
/*File Sockets01.java Copyright 1998, R.G.Baldwin Revised 01/20/98 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. 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. This causes the server to attempt to fetch the specified file and send it to the client. Then the program reads lines from the input stream and displays them on the standard output device. 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. As of 01/20/98, the output from this program was as follows. This is a text representation of an html file named Test01.html. Note that the contents of this test file on the server may change over time, so you may not see exactly the same result when you compile and run this program. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> <HTML> <HEAD> <TITLE></TITLE> <META NAME="Author" CONTENT=""> <META NAME="GENERATOR" CONTENT= "Mozilla/3.01Gold (Win95; I) [Netscape]"> </HEAD> <BODY> <P><B><I>Richard G Baldwin (512) 223-4758, <A HREF="mailto:baldwin@austin.cc.tx.us"> baldwin@austin.cc.tx.us</A>, <A HREF="http://www2.austin.cc.tx.us/baldwin/"> http://www2.austin.cc.tx.us/baldwin/</A></I></B></P> <H3 ALIGN=CENTER> <A HREF="http://www2.austin.cc.tx.us/baldwin/"> Test File</A></H3> <P>This test file is used to test certain network programming applications.</P> </BODY> </HTML> **********************************************************/ import java.net.*; import java.io.*; class Sockets01{ public static void main(String[] args){ String server = "www2.austin.cc.tx.us";//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 outputStream.println("GET /baldwin/Test01.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 Sockets01 //=======================================================// |
This sample program is a simple SMTP client implemented using sockets.
The program implements enough of the SMTP protocol to make it capable of sending an email message to someone if you know their email name and the identity of their SMTP server.
You must be logged onto an appropriate network for this program to run properly. Otherwise, it will throw an exception of type UnknownHostException.
The program begins by instantiating a String object containing the name of an SMTP server. Although I tested this program using my SMTP server, I removed the name of my server from the program to avoid getting lots of test messages from other people who might be testing this program. It should be easy enough for you to obtain the identify of your own SMTP server and to test the program by sending messages to yourself.
You should cause the String object mentioned above to contain the name of your email server or the email server that you are using to test the program.
Instantiation of the String containing the name of the SMTP server is followed by declaration and initialization of an int variable identifying the port number for the standard SMTP mail service. The standard SMTP port is port 25.
The program gets a socket connection to port 25 on the SMTP server.
Then the program gets input and output streams from the socket as in the previous programs.
Once the connection is made and the input and output streams are ready to use, the program begins the conversation with the email server by implementing an abbreviated version of the SMTP protocol.
The SMTP protocol consists of transmitting a series of simple lines of text to the server and listening for lines of text being returned. In this program, the text that is received by the client is displayed on the standard output device, and is shown below.
After the test message has been sent, the program closes the socket and terminates.
This program was tested using JDK 1.1.3 under Win95.
As of 01/20/98, the output from this program (with line breaks manually
inserted) was as follows.
220 monk.austin.cc.tx.us ESMTP Sendmail 8.8.5/8.6.9 ready at Tue, 20 Jan 1998 22:16:37 -0600 250 baldwin... Sender ok 250 baldwin... Recipient ok 354 Enter mail, end with "." on a line by itself |
String server = "put your email server name here"; int port = 25; //mail port |
The purpose of this program is to send an email message to someone,
so at this point, we begin the conversation with the mail server by sending
a line of text in the following format. This line of text identifies the
sender of the message. Then we read and display a line.
//Begin the conversation with the email server. outputStream.println( "mail from: put your email name here"); System.out.println(inputStream.readLine()); |
outputStream.println( "rcpt to: " + "put your email name here"); System.out.println(inputStream.readLine()); |
If we were really serious about writing a program that could handle this protocol, we would need to examine the text coming from the server to confirm that everything is working as expected, and take corrective action if it isn't. This would require considerably more study of the protocol specification than I have done at this point in time.
Next, we send the string "data", and as usual, we read and display
a line of text from the server.
outputStream.println("data"); System.out.println(inputStream.readLine()); |
String timeStamp = (new Date()).toString(); outputStream.println("Test message " + timeStamp); outputStream.println("."); System.out.println(inputStream.readLine()); socket.close(); |
As indicated above, using this protocol would have involved considerably more code if we had been careful to adhere to the specification exactly, and had examined each of the messages received from the server to confirm that everything was going OK.
/*File Sockets02.java Copyright 1998, R.G.Baldwin Revised 01/20/98 This program is a simple SMTP (email) client implemented using sockets. The program implements enough of the SMTP protocol to make it capable of sending an email message to someone at an SMTP 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 instantiating a String object containing the name of an email server. Although I tested this program using my server, I removed the name of my server to avoid getting hundreds of test messages from people around the world testing this program. You should cause the String object to contain the name of your email server or the email server that you are using to test the program. This is followed by declaration and initialization of an int variable containing the port number for the standard SMTP mail service. The standard SMTP port is number 25. Than the program gets a socket connection to port 25 on the email 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 program begins the conversation with the email server following the SMTP protocol. This consists of transmitting a series of simple lines of text to the server and listening for lines of text being returned. The text that is received by the client is displayed on the standard output device, and is shown below. After the test message has been sent, the program closes the socket and terminates. This program was tested using JDK 1.1.3 under Win95. As of 01/20/98, the output from this program (with line breaks manually inserted) was as follows. 220 monk.austin.cc.tx.us ESMTP Sendmail 8.8.5/8.6.9 ready at Tue, 20 Jan 1998 22:16:37 -0600 250 baldwin... Sender ok 250 baldwin... Recipient ok 354 Enter mail, end with "." on a line by itself **********************************************************/ import java.net.*; import java.io.*; import java.util.*; class Sockets02{ public static void main(String[] args){ String server = "put your email server name here"; int port = 25; //mail 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); //Begin the conversation with the email server. outputStream.println( "mail from: put your email name here"); System.out.println(inputStream.readLine()); outputStream.println( "rcpt to: " + "put your email name here"); System.out.println(inputStream.readLine()); outputStream.println("data"); System.out.println(inputStream.readLine()); String timeStamp = (new Date()).toString(); outputStream.println("Test message " + timeStamp); outputStream.println("."); 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 Sockets02 //=======================================================// |
The real complexity, to the extent that there may complexity, is wrapped up in understanding and implementing the various protocols required by the servers for the different services that are offered.
-end-