Socket Programming in Java - Socket programming in the real world, continued
(Page 4 of 4 )
Next comes the ConnectionHandler class. The important aspect of this class is that it is a static inner class of the FileServer class. The tasks carried out by this class are:
- Starting the thread; this is done in the constructor of the class.
- Send the list of downloadable files; the sendIndex() method contains the logic for sending the list.
- Sending the selected file, which is performed by the sendFile() method
- Communicating with the client, which is done in the run() method. This method also calls other methods as required.
The following is the implementation. The class is:
import java.net.*;
import java.io.*;
public class FileServer {
static final int LISTENING_PORT = 3210;
public static void main(String[] args) {
File directory; // The directory from which the
// gets the files that it serves.
ServerSocket listener; // Listens for connection requests.
Socket connection; // A socket for communicating with
// a client.
/* Check that there is a command-line argument.
If not, print a usage message and end. */
if (args.length == 0) {
System.out.println("Usage: java FileServer <directory>");
return;
}
/* Get the directory name from the command line, and make
it into a file object. Check that the file exists and
is in fact a directory. */
directory = new File(args[0]);
if ( ! directory.exists() ) {
System.out.println("Specified directory does not exist.");
return;
}
if (! directory.isDirectory() ) {
System.out.println("The specified file is not a directory.");
return;
}
/* Listen for connection requests from clients. For
each connection, create a separate Thread of type
ConnectionHandler to process it. The ConnectionHandler
class is defined below. The server runs until the
program is terminated, for example by a CONTROL-C. */
try {
listener = new ServerSocket(LISTENING_PORT);
System.out.println("Listening on port " + LISTENING_PORT);
while (true) {
connection = listener.accept();
new ConnectionHandler(directory,connection);
}
}
catch (Exception e) {
System.out.println("Server shut down unexpectedly.");
System.out.println("Error: " + e);
return;
}
} // end main()
static class ConnectionHandler extends Thread {
// An object of this class is a thread that will
// process the connection with one client. The
// thread starts itself in the constructor.
File directory; // The directory from which files are served
Socket connection; // A connection to the client.
TextReader incoming; // For reading data from the client.
PrintWriter outgoing; // For transmitting data to the client.
ConnectionHandler(File dir, Socket conn) {
// Constructor. Record the connection and
// the directory and start the thread running.
directory = dir;
connection = conn;
start();
}
void sendIndex() throws Exception {
// This is called by the run() method in response
// to an "index" command. Send the list of files
// in the directory.
String[] fileList = directory.list();
for (int i = 0; i < fileList.length; i++)
outgoing.println(fileList[i]);
outgoing.flush();
outgoing.close();
if (outgoing.checkError())
throw new Exception("Error while transmitting data.");
}
void sendFile(String fileName) throws Exception {
// This is called by the run() command in response
// to "get <fileName>" command. If the file doesn't
// exist, send the message "error". Otherwise,
// send the message "ok" followed by the contents
// of the file.
File file = new File(directory,fileName);
if ( (! file.exists()) || file.isDirectory() ) {
// (Note: Don't try to send a directory, which
// shouldn't be there anyway.)
outgoing.println("error");
}
else {
outgoing.println("ok");
TextReader fileIn = new TextReader( new FileReader(file) );
while (fileIn.peek() != '') {
// Read and send lines from the file until
// an end-of-file is encountered.
String line = fileIn.getln();
outgoing.println(line);
}
}
outgoing.flush();
outgoing.close();
if (outgoing.checkError())
throw new Exception("Error while transmitting data.");
}
public void run() {
// This is the method that is executed by the thread.
// It creates streams for communicating with the client,
// reads a command from the client, and carries out that
// command. The connection is logged to standard output.
// An output beginning with ERROR indicates that a network
// error occurred. A line beginning with OK means that
// there was no network error, but does not imply that the
// command from the client was a legal command.
String command = "Command not read";
try {
incoming = new TextReader( connection.getInputStream() );
outgoing = new PrintWriter( connection.getOutputStream() );
command = incoming.getln();
if (command.equals("index")) {
sendIndex();
}
else if (command.startsWith("get")){
String fileName = command.substring(3).trim();
sendFile(fileName);
}
else {
outgoing.println("unknown command");
outgoing.flush();
}
System.out.println("OK " + connection.getInetAddress() + " " + command);
}
catch (Exception e) {
System.out.println("ERROR " + connection.getInetAddress() + " " + command + " " + e);
}
finally {
try {
connection.close();
}
catch (IOException e) {
}
}
}
} // end nested class ConnectionHandler
}
That completes the implementation of the File Server. The discussion has left out the UDP based sockets. I will be dealing with that in the next article. Till then…
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |