9. Program source code
9.1. The generic TCP client
Many services created at the dawn of the Internet operate according to the echo server model studied previously: client-server exchanges consist of exchanging lines of text. We will write a generic TCP client that will be launched as follows: java cltTCPgenerique server port
This TCP client will connect to the server's port. Once connected, it will create two threads:
- one thread responsible for reading commands typed on the keyboard and sending them to the server
- a thread responsible for reading the server's responses and displaying them on the screen
Why two threads? Each TCP-IP service has its own specific protocol, and the following situations sometimes arise:
- the client must send several lines of text before receiving a response
- a server’s response may contain multiple lines of text
Therefore, the loop that sends a single line to the server and receives a single line from the server is not always suitable. We will therefore create two separate loops:
- a loop to read commands typed on the keyboard to be sent to the server. The user will signal the end of commands with the keyword "fin".
- a loop to receive and display the server’s responses. This will be an infinite loop that will only be interrupted by the server closing the network connection or by the user typing the “end” command at the keyboard.
To have these two separate loops, we need two independent threads. Let’s look at an example of execution where our generic TCP client connects to an SMTP (Simple Mail Transfer Protocol) service. This service is responsible for routing email to its recipients. It operates on port 25 and uses a text-based exchange protocol.
Dos>java genericTCPclient istia.univ-angers.fr 25
Commands:
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
help
<-- 502 5.3.0 Sendmail 8.11.6 -- HELP not implemented
mail from: machin@univ-angers.fr
<-- 250 2.1.0 machin@univ-angers.fr... Sender ok
rcpt to: serge.tahe@istia.univ-angers.fr
<-- 250 2.1.5 serge.tahe@istia.univ-angers.fr... Recipient ok
data
<-- 354 Enter mail, end with "." on a line by itself
Subject: test
line1
line2
line3
.
<-- 250 2.0.0 g4D6bks25951 Message accepted for delivery
quit
<-- 221 2.0.0 istia.univ-angers.fr closing connection
[end of thread reading server responses]
end
[end of the thread sending commands to the server]
Let's comment on these client-server exchanges:
- The SMTP service sends a welcome message when a client connects to it:
- Some services have a "help" command that provides information on the commands available for that service. That is not the case here. The SMTP commands used in the example are as follows:
- mail from: sender, to specify the sender’s email address
- rcpt to: recipient, to specify the email address of the message’s recipient. If there are multiple recipients, the rcpt to: command is repeated as many times as necessary for each recipient.
- data, which signals to the SMTP server that the message is about to be sent. As indicated in the server’s response, this is a sequence of lines ending with a line containing only a period. A message may have headers separated from the message body by a blank line. In our example, we included a subject using the Subject: keyword
- Once the message is sent, we can tell the server that we are done using the quit command. The server then closes the network connection. The read thread can detect this event and stop.
- The user then types "end" on the keyboard to also stop the thread reading the commands typed on the keyboard.
If we check the received email, we see the following (Outlook):

Note that the SMTP service cannot detect whether a sender is valid or not. Therefore, you can never trust the "From" field of a message. In this case, the sender machin@univ-angers.fr did not exist.
This generic TCP client allows us to discover the communication protocol of Internet services and, from there, build specialized classes for clients of these services. Let’s explore the communication protocol of the POP (Post Office Protocol) service, which allows us to retrieve emails stored on a server. It operates on port 110.
Dos> java clientTCPgenerique istia.univ-angers.fr 110
Commands:
<-- +OK Qpopper (version 4.0.3) at istia.univ-angers.fr starting.
help
<-- -ERR Unknown command: "help".
user st
<-- +OK Password required for st.
pass mypassword
<-- +OK st has 157 visible messages (0 hidden) in 11,755,927 bytes.
list
<-- +OK 157 visible messages (11,755,927 bytes)
<-- 1 892847
<-- 2 171,661
...
<-- 156 2843
<-- 157 2796
<-- .
retr 157
<-- +OK 2796 bytes
<-- Received: from lagaffe.univ-angers.fr (lagaffe.univ-angers.fr [193.49.144.1])
<-- by istia.univ-angers.fr (8.11.6/8.9.3) with ESMTP id g4D6wZs26600;
<-- Mon, May 13, 2002 08:58:35 +0200
<-- Received: from jaume ([193.49.146.242])
<-- by lagaffe.univ-angers.fr (8.11.1/8.11.2/GeO20000215) with SMTP id g4D6wSd37691;
<-- Mon, May 13, 2002 08:58:28 +0200 (CEST)
...
<-- ------------------------------------------------------------------------
<-- NOC-RENATER2 Tel.: 0800 77 47 95
<-- Fax: (+33) 01 40 78 64 00, Email: noc-r2@cssi.renater.fr
<-- ------------------------------------------------------------------------
<--
<-- .
quit
<-- +OK Pop server at istia.univ-angers.fr signing off.
[end of thread reading server responses]
end
[end of thread sending commands to the server]
The main commands are as follows:
- user login, where you enter your login on the machine that hosts your emails
- pass password, where you enter the password associated with the previous login
- list, to get a list of messages in the format number, size in bytes
- retr i, to read message number i
- quit, to end the session.
Let’s now explore the communication protocol between a client and a web server, which typically runs on port 80:
Dos> java clientTCPgenerique istia.univ-angers.fr 80
Commands:
GET /index.html HTTP/1.0
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
<--
<-- <head>
<-- <meta http-equiv="Content-Type"
<-- content="text/html; charset=iso-8859-1">
<-- <meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<-- <title>Welcome to ISTIA - University of Angers</title>
<-- </head>
....
<-- face="Verdana"> - Last updated on <b>January 10, 2002</b></font></p>
<-- </body>
<-- </html>
<--
[end of thread displaying server responses]
end
[end of the thread for sending commands to the server]
A web client sends its commands to the server according to the following pattern:
The web server responds only after receiving the empty line. In this example, we used only one command:
which requests the URL /index.html from the server and indicates that it is using HTTP version 1.0. The most recent version of this protocol is 1.1. The example shows that the server responded by sending the contents of the index.html file and then closed the connection, as we can see the response reading thread terminating. Before sending the contents of the index.html file, the web server sent a series of headers followed by an empty line:
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
The line <html> is the first line of the /index.html file. The preceding text is called HTTP (HyperText Transfer Protocol) headers. We won’t go into detail about these headers here, but keep in mind that our generic client provides access to them, which can be helpful for understanding them. For example, the first line:
indicates that the contacted web server supports the HTTP/1.1 protocol and that it successfully found the requested file (200 OK), where 200 is an HTTP response code. The lines
tell the client that it will receive 11,251 bytes of HTML (HyperText Markup Language) text and that the connection will be closed once the data has been sent.
So here we have a very handy TCP client. It certainly does less than the telnet program we used earlier, but it was interesting to write it ourselves. The generic TCP client program is as follows:
// imported packages
import java.io.*;
import java.net.*;
public class genericTCPclient{
// receives the characteristics of a service as a parameter in the form
// server port
// connects to the service
// creates a thread to read commands typed on the keyboard
// these will be sent to the server
// creates a thread to read responses from the server
// these will be displayed on the screen
// the process ends when the "end" command is typed
// instance variable
private static Socket client;
public static void main(String[] args){
// syntax
final String syntax = "pg server port";
// number of arguments
if(args.length != 2)
error(syntax, 1);
// note the server name
String server = args[0];
// the port must be an integer greater than 0
int port = 0;
boolean portError = false;
Exception e = null;
try {
port = Integer.parseInt(args[1]);
} catch (Exception e) {
E = e;
portError = true;
}
portError = portError || port <= 0;
if(portError)
error(syntax + "\n" + "Incorrect port (" + E + ")", 2);
client = null;
// there may be issues
try{
// connect to the service
client = new Socket(server, port);
} catch (Exception ex) {
// error
error("Unable to connect to the service ("+ server
+","+port+"), error: "+ex.getMessage(),3);
// end
return;
}//catch
// create read/write threads
new ClientSend(client).start();
new ClientReceive(client).start();
// end of main thread
return;
}// main
// display errors
public static void error(String msg, int exitCode){
// display error
System.err.println(msg);
// exit with error
System.exit(exitCode);
}//error
}//class
class ClientSend extends Thread {
// class responsible for reading commands typed on the keyboard
// and sending them to a server via a TCP client passed as a parameter
private Socket client; // the TCP client
// constructor
public ClientSend(Socket client){
// store the TCP client
this.client = client;
}//constructor
// thread's Run method
public void run(){
// local data
PrintWriter OUT = null; // network write stream
BufferedReader IN = null; // keyboard stream
String command = null; // command read from keyboard
// error handling
try{
// Create network write stream
OUT = new PrintWriter(client.getOutputStream(), true);
// create keyboard input stream
IN = new BufferedReader(new InputStreamReader(System.in));
// loop for command input and transmission
System.out.println("Commands: ");
while(true){
// Read command typed on the keyboard
command = IN.readLine().trim();
// Done?
if (command.toLowerCase().equals("end")) break;
// send command to server
OUT.println(command);
// next command
}//while
} catch (Exception ex) {
// error
System.err.println("Sending: The following error occurred: " + ex.getMessage());
}//catch
// end - closing the streams
try{
OUT.close(); client.close();
}catch(Exception ex){}
// signal the end of the thread
System.out.println("[Send: end of the thread sending commands to the server]");
}//run
}//class
class ClientReceive extends Thread{
// class responsible for reading text lines intended for a
// TCP client passed as a parameter
private Socket client; // the TCP client
// constructor
public ClientReceive(Socket client){
// store the TCP client
this.client = client;
}//constructor
// thread's Run method
public void run(){
// local data
BufferedReader IN = null; // network read stream
String response = null; // server response
// error handling
try{
// Create network read stream
IN = new BufferedReader(new InputStreamReader(client.getInputStream()));
// Loop to read text lines from the IN stream
while(true){
// read network stream
response = IN.readLine();
// Is the stream closed?
if(response == null) break;
// Display
System.out.println("<-- " + response);
}//while
} catch (Exception ex) {
// error
System.err.println("Reception: The following error occurred: " + ex.getMessage());
}//catch
// end - closing the streams
try{
IN.close(); client.close();
}catch(Exception ex){}
// signal the end of the thread
System.out.println("[Receive: end of thread reading responses from the server]");
}//run
}//class
9.2. The generic TCP server
Now we'll look at a server
- that displays on the screen the commands sent by its clients
- and sends them, in response, the lines of text typed on the keyboard by a user. It is therefore the user who acts as the server.
The program is launched by: java genericTCPserver listeningPort, where listeningPort is the port to which clients must connect. Client service will be handled by two threads:
- one thread dedicated exclusively to reading the text lines sent by the client
- a thread dedicated exclusively to reading the responses typed on the keyboard by the user. This thread will signal, using the `fin` command, that it is closing the connection with the client.
The server creates two threads per client. If there are n clients, there will be 2n active threads at the same time. The server itself never stops unless the user presses Ctrl-C on the keyboard. Let’s look at a few examples.
The server is running on port 100, and we use the generic client to communicate with it. The client window looks like this:
E:\data\serge\MSNET\c#\network\generic tcp client> java genericTCPclient localhost 100
Commands:
command 1 from client 1
<-- response 1 to client 1
command 2 from client 1
<-- response 2 to client 1
end
The following error occurred: Unable to read data from the transport connection.
[end of thread reading server responses]
[end of the thread sending commands to the server]
Lines beginning with <-- are those sent from the server to the client; the others are from the client to the server. The server window is as follows:
Dos> java genericTCPserver 100
Generic server launched on port 100
Thread for reading server responses to client 1 launched
1: Thread for reading requests from client 1 launched
<-- command 1 from client 1
Response 1 to client 1
1: <-- command 2 from client 1
response 2 to client 1
1: [End of thread reading requests from client 1]
end
[end of thread reading server responses to client 1]
Lines beginning with <-- are those sent from the client to the server. Lines N: are those sent from the server to client N. The server above is still active even though client 1 has finished. We launch a second client for the same server:
Dos> java clientTCPgenerique localhost 100
Commands:
command 3 from client 2
<-- response 3 to client 2
end
The following error occurred: Unable to read data from the transport connection.
[end of thread reading server responses]
[end of the thread sending commands to the server]
The server window then looks like this:
Dos> java genericTCPserver 100
Generic server running on port 100
Thread for reading server responses to client 1 launched
1: Thread for reading requests from client 1 launched
<-- Command 1 from client 1
Response 1 to client 1
1: <-- command 2 from client 1
response 2 to client 1
1: [End of thread reading requests from client 1]
end
[end of thread reading server responses to client 1]
Thread for reading server responses to client 2 launched
2: Thread for reading requests from client 2 launched
<-- command 3 from client 2
response 3 to client 2
2: [End of thread reading requests from client 2]
end
[end of thread reading server responses to client 2]
^C
Now let's simulate a web server by running our generic server on port 88:
Dos> java genericTCPserver 88
Generic server launched on port 88
Now let’s open a browser and request the URL http://localhost:88/exemple.html. The browser will then connect to port 88 on the localhost machine and request the /example.html page:

Now let’s look at our server window:
Dos>java genericTCPserver 88
Generic server launched on port 88
Thread for reading server responses to client 2 launched
2: Thread for reading requests from client 2 launched
<-- GET /example.html HTTP/1.1
<-- Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/msword, */*
<-- Accept-Language: fr
<-- Accept-Encoding: gzip, deflate
<-- User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.0.2
914)
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
This reveals the HTTP headers sent by the browser. This allows us to gradually learn about the HTTP protocol. In a previous example, we created a web client that sent only the GET command. That was sufficient. Here we see that the browser sends other information to the server. This information is intended to tell the server what type of client it is dealing with. We also see that the HTTP headers end with an empty line.
Let’s craft a response for our client. The user at the keyboard is the actual server here and can manually craft a response. Recall the response sent by a web server in a previous example:
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
Let's try to provide a similar response:
...
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
2: HTTP/1.1 200 OK
2: Server: generic TCP server
2: Connection: close
2: Content-Type: text/html
2 :
2: <html>
2 : <head><title>Generic server</title></head>
2 : <body>
2 : <center>
2 : <h2>Response from the generic server</h2>
2 : </center>
2: </body>
2: </html>
2: end
The following error occurred: Unable to read data from the transport connection.
[end of thread reading requests from client 2]
[end of thread reading server responses to client 2]
Lines beginning with 2: are sent from the server to client #2. The end command closes the connection from the server to the client. In our response, we have limited ourselves to the following HTTP headers:
We do not specify the size of the file we are sending (Content-Length), but simply indicate that we will close the connection (Connection: close) after sending it. This is sufficient for the browser. Upon seeing the connection closed, it will know that the server’s response is complete and will display the HTML page that was sent to it. The page is as follows:
2: <html>
2: <head><title>Generic server</title></head>
2 : <body>
2 : <center>
2 : <h2>Generic server response</h2>
2 : </center>
2: </body>
2: </html>
The user then closes the connection to the client by typing the "fin" command. The browser then knows that the server's response is complete and can display it:

If, in the example above, you select View/Source to see what the browser received, you get:

that is, exactly what was sent from the generic server.
The code for the generic TCP server is as follows:
// packages
import java.io.*;
import java.net.*;
public class genericTCPserver{
// main program
public static void main(String[] args) {
// receives the port to listen for client requests
// creates a thread to read client requests
// these will be displayed on the screen
// creates a thread to read commands typed on the keyboard
// these will be sent as a response to the client
// the process ends with the "end" command typed on the keyboard
final String syntax = "Syntax: pg port";
// instance variable
// is there an argument
if(args.length != 1)
error(syntax, 1);
// the port must be an integer > 0
int port = 0;
boolean portError = false;
Exception e = null;
try{
port = Integer.parseInt(args[0]);
} catch (Exception e) {
E = e;
portError = true;
}
portError = portError || port <= 0;
if(portError)
error(syntax + "\n" + "Incorrect port (" + E + ")", 2);
// create the listening service
ServerSocket listener = null;
int clients = 0; // number of clients handled
try{
// Create the service
listen = new ServerSocket(port);
// monitoring
System.out.println("Generic server launched on port " + port);
// client service loop
Socket client = null;
while (true) { // infinite loop - will be stopped by Ctrl-C
// waiting for a client
client = listen.accept();
// the service is handled by separate threads
nbClients++;
// create read/write threads
new ServerSend(client, nbClients).start();
new ReceiveServer(client, nbClients).start();
// return to listening for requests
}// end of while
} catch (Exception ex) {
// report the error
error("The following error occurred: " + ex.getMessage(), 3);
}//catch
}// end main
// display errors
public static void error(String msg, int exitCode){
// display error
System.err.println(msg);
// exit with error
System.exit(exitCode);
}//error
}//class
class ServerSend extends Thread{
// class responsible for reading keyboard input
// and sending them to a client via a TCP client passed to the constructor
Socket client; // the TCP client
int clientNumber; // client number
// constructor
public ServerSend(ClientSocket, int clientNumber){
// store the TCP client
this.client = client;
// and its number
this.clientNumber = clientNumber;
}//constructor
// thread's Run method
public void run(){
// local data
PrintWriter OUT = null; // network write stream
String response = null; // response read from keyboard
BufferedReader IN = null; // keyboard stream
// tracking
System.out.println("Thread for reading server responses to client " + numClient + " started");
// error handling
try{
// Create network write stream
OUT = new PrintWriter(client.getOutputStream(), true);
// Create keyboard stream
IN = new BufferedReader(new InputStreamReader(System.in));
// loop for command input and transmission
while(true){
// client identification
System.out.print("--> " + clientNumber + " : ");
// read response typed on the keyboard
response = IN.readLine().trim();
// Done?
if (response.toLowerCase().equals("end")) break;
// send response to the server
OUT.println(response);
// next response
}//while
} catch (Exception ex) {
// error
System.err.println("The following error occurred: " + ex.getMessage());
}//catch
// end - closing streams
try{
OUT.close(); client.close();
}catch(Exception ex){}
// signal the end of the thread
System.out.println("[End of thread reading server responses to client " + numClient + "]");
}//run
}//class
class ServerReceive extends Thread{
// Class responsible for reading the text lines sent to the server
// via a TCP client passed to the constructor
Socket client; // the TCP client
int clientNumber; // client number
// constructor
public ServerReceive(ClientSocket, int clientNumber) {
// store the TCP client
this.client = client;
// and its number
this.clientNumber = clientNumber;
}//constructor
// thread's Run method
public void run(){
// local data
BufferedReader IN = null; // network read stream
String response = null; // server response
// monitoring
System.out.println("Thread for reading requests from client " + numClient + " started");
// error handling
try{
// Create network read stream
IN = new BufferedReader(new InputStreamReader(client.getInputStream()));
// Loop to read text lines from the IN stream
while(true){
// read network stream
response = IN.readLine();
// Is the stream closed?
if(response == null) break;
// display
System.out.println("<-- " + response);
}//while
} catch (Exception ex) {
// error
System.err.println("The following error occurred: " + ex.getMessage());
}//catch
// end - closing streams
try{
IN.close(); client.close();
}catch(Exception ex){}
// signal the end of the thread
System.out.println("[End of thread reading client requests " + numClient + "]");
}//run
}//class