• No results found

Establishing a Data Connection

Whenever an FTP server needs to transfer raw data to or from a client, it uses a separate data connection for the transfer. Normally, the client sets up a listen socket (in Java, a ServerSocket) to accept an incoming connection from the FTP server. The client then sends the host address and port number of the listen socket to the server using the PORT command. The format of the PORT command is:

PORT h1,h2,h3,h4,p1,p2

The h1-h4 parameters are the individual bytes in the client's host address. If the client's host address was 192.0.0.1, the

bytes would be 192,0,0,1. The p1 and p2 parameters are the upper and lower bytes of the listen socket's port number. The following code fragment extracts p1 and p2 from a port number:

int p1 = (portNumber >> 8) & 0xff; int p2 = portNumber & 0xff;

An example PORT command for a host with an address is 192.0.0.3 and a port number of 1234 is:

PORT 192,0,0,3,4,210

You can verify that the port bytes of 4 and 210 are indeed port 1234 by computing (p1*256) + p2, or (4*256) + 210.

Once you send the PORT command, you can issue a command that requires a data connection like RETR, STOR, or LIST. Once you issue a command that requires a data connection, the server will connect to the listen socket and either send or receive data, depending on the command. Figure 8.2 shows the typical interaction sequence between an FTP server and a client performing a RETR command.

Figure 8.2 : A server connects to a client to establish a data connection.

The normal method of data connection will not work for Java applet because an applet may not accept an incoming socket connection. Fortunately, the FTP protocol gives you another option for establishing a data connection-the PASV command.

The PASV command is similar to the PORT command, except that it causes the server to create the listen socket. The response from the PASV command gives the host address and port number for the listen socket in the same

h1,h2,h3,h4,p1,p2 format as used in the PORT command. Here is an example PASV command and the response from the server:

PASV

Chapter 8 -- Reading and Writing Files from an Applet

227 Entering Passive Mode (127,0,0,1,6,114)

Once the server returns the response, the client can establish the data connection. Figure 8.3 shows the typical interaction sequence between an FTP server and a client performing a STOR command, using PASV to set up the data connection.

Figure 8.3 : The PASV command forces the server to create the listen socket for the data connection.

Listing 8.5 shows the doPasvPort method from the FTPSession class. It sends a PASV command, parses the response, and then establishes a socket connection with the server.

Listing 8.5 doPasvPort Method from FTPSession.java

protected synchronized Socket doPasvPort() throws IOException

{

// Send the PASV command

String response = doCommand("PASV"); // If it wasn't in the 200s, there was an error if (response.charAt(0) != '2') {

throw new IOException(response); }

// The pasv response looks like:

// 227 Entering Passive Mode (127,0,0,1,4,160) // We'll look for the ()'s at the end first

int parenStart = response.lastIndexOf('('); int parenEnd = response.lastIndexOf(')');

// Make sure they're both there and that the ) comes after the ( if ((parenStart < 0) || (parenEnd < 0) ||

(parenStart >= parenEnd)) {

throw new IOException("PASV response format error"); }

// Extract the address bytes

String pasvAddr = response.substring(parenStart+1, parenEnd); // Create a tokenizer to parse the bytes

StringTokenizer tokenizer = new StringTokenizer(pasvAddr, ","); // Create the array to store the bytes

int[] addrValues = new int[6]; // Parse each byte

for (int i=0; (i < 6) && tokenizer.hasMoreTokens(); i++) { try {

Chapter 8 -- Reading and Writing Files from an Applet

addrValues[i] = Integer.valueOf(

tokenizer.nextToken()).intValue(); } catch (Exception e) {

throw new IOException(

"PASV response format error"); }

}

// We ignore the host addresses, assuming that the host address is // the same as the host address we used to connect the first time. Socket newSock = new Socket(host, (addrValues[4] << 8) + addrValues[5]);

return newSock; }

Listing 8.6 shows the put method from the FTPSession class. It uses the doPasvPort command to set up a data connection, then sends a STOR command to the FTP server. The STOR command should return a response code in the 100- 199 range, indicating that the STOR may proceed. When you finish sending the file to the FTP server, you must close down the data connection. This tells the server that you have finished. You should then receive another response from the server over the command connection, which should have a response code in the 200-299 range.

Listing 8.6 put Method from FTPSession.java

public synchronized void put(String remoteFile, byte[] data, boolean doBinary)

throws IOException {

// If transferring in binary mode, send a type command for type I (IMAGE) if (doBinary) {

String response = doCommand("TYPE I"); if (response.charAt(0) != '2') {

throw new IOException(response); }

// If transferring in ASCII mode, send a type command for type A (ASCII) } else {

String response = doCommand("TYPE A"); if (response.charAt(0) != '2') {

throw new IOException(response); }

}

// Open up a data connection

Socket putSock = doPasvPort();

Chapter 8 -- Reading and Writing Files from an Applet

// Tell the server where we want it to store the data we are sending String response = doCommand("STOR "+remoteFile);

// If the request is successful, the server should send a response // in the 100s and then start receiving the bytes. Once the data // connection is closed, it should send a response in the 200s. if (response.charAt(0) != '1') {

putSock.close();

throw new IOException(response); }

// If binary mode, just write all the bytes if (doBinary) {

OutputStream out = putSock.getOutputStream(); out.write(data);

// If ASCII mode, write the data a line at a time } else {

DataInputStream in = new DataInputStream( new ByteArrayInputStream(data));

DataOutputStream out = new DataOutputStream( putSock.getOutputStream());

String line;

while ((line = in.readLine()) != null) { out.writeBytes(line+"\r");

} }

putSock.close();

response = getResponse(); // Make sure we got a 200 response

if (response.charAt(0) != '2') {

throw new IOException(response); }

}

The FTPSession class is quite simple to use. You just create an instance of FTPSession by passing the destination host

name, the user name, and the password to the constructor, and then using the get and put methods to retrieve and send files, respectively. Listing 8.7 shows an example applet that copies a file by retrieving it and then storing it under a new name.

Chapter 8 -- Reading and Writing Files from an Applet

Listing 8.7 Source Code for TryFTP.java

import java.applet.*; import java.io.*;

// This applet demonstrates the use of the FTPSession class. // It copies a file called "volcano" to a file called "vol.ftp" // by fetching the file and then storing it with a new name. public class TryFTP extends Applet

{

public void init() {

try {

// Create the session to host 192.0.0.3, using a user name of anonymous // and a password of mark@localhost

FTPSession sess = new FTPSession( "192.0.0.3",

"anonymous", "mark@localhost"); // Fetch the file

byte[] file = sess.get("/home/mark/volcano", true); // Store the file

sess.put("/home/mark/vol.ftp", file, true); } catch (Exception e) { e.printStackTrace(); } } } Caution

Be extremely careful when using the FTPSession class with respect to the user name and password. Even though your applet is compiled, it is fairly trivial to look through the code and find the user name and password that are sent. You should either use anonymous FTP, or set up a user account that is not allowed to log on to your system and is allowed to use only FTP. Otherwise, you are broadcasting a free user account all over the Internet whenever you put your applet out there.

file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/f8-1.gif

Chapter 9 -- Creating Reusable Graphics Components

Chapter 9