Reading from a Socket Input Stream
I am trying to use a socket to connect to a FTP site. Everything is fine, except that sometimes, when I try to run multiple RETR commands through the socket to download an entire directory, It most of the time freezes the program. Sometimes it actually will complete. I have a feeling it is a Buffered Reader problem. I am using a Buffered Reader to do the reading and It always seems to get stuck at the same place and I have been changing things for over a week now and i can't figure this out. Here is the code and I will add a comment to where it is getting stuck (it is in the waitForResponse() method. If you have any other comments on how I am trying to write this program I would like to hear them too. Thank you.
import java.io.*;
import java.net.Socket;
import java.util.StringTokenizer;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
// This class extends Socket and is designed specifically be used
// for ftp connections only
//***********************************************************************************
publicclass FuriousFTPSocket{
// fields
//*****************************************************************************
private Socket socket =null;
private BufferedReader reader =null;
private BufferedWriter writer =null;
private String log ="";
private BufferedInputStream infoInput =null;
private Timer keepAliveTimer =new Timer(60000,
new ActionListener()
{
publicvoid actionPerformed(ActionEvent e)
{
try
{
sendCommand("NOOP",false);
waitForResponse(false);
}
catch(IOException ioe)
{
System.out.println("Could not keep connection alive.");
ioe.printStackTrace();
}
}
});
// Creates a FuriousFTP Object
//**********************************************************************************
public FuriousFTPSocket(){
}
// Connects to the default port of an FTP server and logs in as
// anonymous/anonymous.
//**********************************************************************************
publicsynchronizedvoid connect(String host,boolean sendToLog)throws IOException{
connect(host, 21, sendToLog);
}
// Connects to an FTP server on the given port and logs in as
// anonymous/anonymous.
//**********************************************************************************
publicsynchronizedvoid connect(String host,int port,boolean sendToLog)throws IOException{
connect(host, port,"anonymous","anonymous", sendToLog);
}
// Connects to an FTP server on the given port and logs in with the supplied
// username and password.
//**********************************************************************************
publicsynchronizedvoid connect(String host,int port, String user,
String pass,boolean sendToLog)throws IOException
{
if (socket !=null)
{
if(sendToLog) addToLog("FuriousFTP is already connected.");
}
else
{
socket =new Socket(host, port);
//infoInput = new BufferedInputStream(socket.getInputStream());
reader =new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer =new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String response = waitForResponse(sendToLog);
if (!response.startsWith("220")){
thrownew IOException(
"FuriousFTP received an unknown response when connecting to the FTP server: "
+ response);
}
sendLine("USER " + user, sendToLog);
response = waitForResponse(sendToLog);
if (!response.startsWith("331")){
thrownew IOException(
"FuriousFTP received an unknown response after sending the user: "
+ response);
}
sendLine("PASS " + pass, sendToLog);
response = waitForResponse(sendToLog);
if (!response.startsWith("230")){
thrownew IOException(
"FuriousFTP was unable to log in with the supplied password: "
+ response);
}
socket.setSoTimeout(0);
socket.setKeepAlive(true);
keepAliveTimer.start();
}
}
// Disconnects from the FTP server.
//**********************************************************************************
publicsynchronizedvoid disconnect(boolean sendToLog)throws IOException{
try{
sendLine("QUIT", sendToLog);
waitForResponse(sendToLog);
}
finally{
keepAliveTimer.stop();
socket =null;
}
}
// Returns the working directory of the FTP server it is connected to.
//**********************************************************************************
publicsynchronized String pwd(boolean sendToLog)throws IOException{
sendLine("PWD", sendToLog);
String dir =null;
String response = waitForResponse(sendToLog);
if (response.startsWith("257")){
int firstQuote = response.indexOf('\"');
int secondQuote = response.indexOf('\"', firstQuote + 1);
if (secondQuote > 0){
dir = response.substring(firstQuote + 1, secondQuote);
}
}
return dir;
}
// Changes the working directory. Returns true if successful.
//**********************************************************************************
publicsynchronizedboolean cwd(String dir,boolean sendToLog)throws IOException{
sendLine("CWD " + dir, sendToLog);
String response = waitForResponse(sendToLog);
return (response.startsWith("250"));
}
// Sends a file to be stored on the FTP server. Returns true if the file
// transfer was successful. The file is sent in passive mode to avoid NAT or
// firewall problems at the client end.
//**********************************************************************************
publicsynchronizedboolean stor(File file,boolean sendToLog)throws IOException{
if (file.isDirectory()){
thrownew IOException("FuriousFTP cannot upload a directory.");
}
String filename = file.getName();
return stor(new FileInputStream(file), filename, sendToLog);
}
// Sends a file to be stored on the FTP server. Returns true if the file
// transfer was successful. The file is sent in passive mode to avoid NAT or
// firewall problems at the client end.
//**********************************************************************************
publicsynchronizedboolean stor(InputStream inputStream, String filename,boolean sendToLog)
throws IOException{
BufferedInputStream input =new BufferedInputStream(inputStream);
Socket dataSocket = goPassive(sendToLog);
sendLine("STOR " + filename, sendToLog);
String response = waitForResponse(sendToLog);
if (!response.startsWith ("125") && !response.startsWith("150 ")){
thrownew IOException("FuriousFTP was not allowed to send the file: "
+ response);
}
BufferedOutputStream output =new BufferedOutputStream(dataSocket
.getOutputStream());
byte[] buffer =newbyte[4096];
int bytesRead = 0;
while ((bytesRead = input.read(buffer)) != -1){
output.write(buffer, 0, bytesRead);
}
output.flush();
output.close();
input.close();
response = waitForResponse(sendToLog);
return response.startsWith("226");
}
// Enter binary mode for sending binary files.
//**********************************************************************************
publicsynchronizedboolean bin(boolean sendToLog)throws IOException{
sendLine("TYPE I", sendToLog);
String response = waitForResponse(sendToLog);
return (response.startsWith("200"));
}
// Enter ASCII mode for sending text files. This is usually the default mode.
// Make sure you use binary mode if you are sending images or other binary
// data, as ASCII mode is likely to corrupt them.
//**********************************************************************************
publicsynchronizedboolean ascii(boolean sendToLog)throws IOException{
sendLine("TYPE A", sendToLog);
String response = waitForResponse(sendToLog);
return (response.startsWith("200"));
}
// Sends a raw command to the FTP server.
//**********************************************************************************
privatesynchronizedvoid sendLine(String line,boolean sendToLog)
throws IOException
{
if (socket ==null)
{
addToLog("FuriousFTP is not connected.");
}
else{
try{
writer.write(line +"\r\n");
writer.flush();
if(sendToLog) addToLog("> " + line);
}catch (IOException e)
{
System.out.println("problem while sending command");
e.printStackTrace();
}
}
}
// Reads a line from the Buffered Reader
//*************************************************************
privatesynchronized String readLine(boolean sendToLog)
throws IOException
{
String line = reader.readLine();
//String line = waitForResponse(sendToLog);
if(sendToLog) addToLog("< " + line);
return line;
}
// the method that the console calls to send a raw ftp command
//****************************************************************
publicsynchronizedvoid sendCommand(String command,
boolean sendToLog)
{
if (socket ==null){
if(sendToLog) addToLog("FuriousFTP is not connected.");
}
else{
try
{
sendLine(command, sendToLog);
waitForResponse(sendToLog);
}
catch(IOException e)
{
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
publicsynchronized Socket goPassive(boolean sendToLog)
throws IOException
{
sendLine("PASV", sendToLog);
String response = waitForResponse(sendToLog);
if (!response.startsWith("227"))
{
System.out.println("error while attempting passive mode");
thrownew IOException("FuriousFTP could not request passive mode: "
+ response);
}
String ip =null;
int port = -1;
int opening = response.indexOf('(');
int closing = response.indexOf(')', opening + 1);
if (closing > 0){
String dataLink = response.substring(opening + 1, closing);
StringTokenizer tokenizer =new StringTokenizer(dataLink,",");
try{
ip = tokenizer.nextToken() +"." + tokenizer.nextToken() +"."
+ tokenizer.nextToken() +"." + tokenizer.nextToken();
port = Integer.parseInt(tokenizer.nextToken()) * 256
+ Integer.parseInt(tokenizer.nextToken());
}catch (Exception e){
System.out.println("bad data link information");
thrownew IOException("FuriousFTP received bad data link information: "
+ response);
}
}
returnnew Socket(ip, port);
}
publicsynchronized String list(boolean sendToLog)
throws IOException
{
if (socket ==null){
if(sendToLog) addToLog("FuriousFTP is not connected.");
returnnull;
}
else{
ascii(sendToLog);
String outputString ="";
Socket dataSocket = goPassive(sendToLog);
BufferedInputStream input =new BufferedInputStream(dataSocket.getInputStream());
sendLine("LIST", sendToLog);
String response = waitForResponse(sendToLog);
if (!response.startsWith ("125") && !response.startsWith("150 ")){
System.out.println("error while getting list");
thrownew IOException("FuriousFTP was not allowed to retrieve the list: "
+ response);
}
ByteArrayOutputStream byteList =new ByteArrayOutputStream();
BufferedOutputStream output =new BufferedOutputStream(byteList);
byte[] buffer =newbyte[4096];
int bytesRead = 0;
while ((bytesRead = input.read(buffer)) != -1){
output.write(buffer, 0, bytesRead);
}
output.flush();
output.close();
input.close();
response = waitForResponse(sendToLog);
outputString = byteList.toString();
if(sendToLog) addToLog(outputString);
return outputString;
}
}
publicsynchronized String nlst(boolean sendToLog)
throws IOException
{
if (socket ==null){
if(sendToLog) addToLog("FuriousFTP is not connected.");
returnnull;
}
else
{
ascii(sendToLog);
String outputString ="";
Socket dataSocket = goPassive(sendToLog);
BufferedInputStream input =new BufferedInputStream(dataSocket.getInputStream());
sendLine("NLST", sendToLog);
String response = waitForResponse(sendToLog);
if (!response.startsWith ("125") && !response.startsWith("150 ")){
System.out.println("error during nlst");
thrownew IOException("FuriousFTP was not allowed to retrieve the list: "
+ response);
}
ByteArrayOutputStream byteList =new ByteArrayOutputStream();
BufferedOutputStream output =new BufferedOutputStream(byteList);
byte[] buffer =newbyte[4096];
int bytesRead = 0;
while ((bytesRead = input.read(buffer)) != -1){
output.write(buffer, 0, bytesRead);
}
output.flush();
output.close();
input.close();
response = waitForResponse(sendToLog);
outputString = byteList.toString();
if(sendToLog) addToLog(outputString);
return outputString;
}
}
publicsynchronized File retr(String fileName,boolean sendToLog)
throws IOException
{
if (socket ==null){
if(sendToLog) addToLog("FuriousFTP is not connected.");
returnnull;
}
else{
bin(sendToLog);
Socket dataSocket = goPassive(sendToLog);
BufferedInputStream input =new BufferedInputStream(dataSocket.getInputStream());
sendLine("RETR " + fileName, sendToLog);
String response = waitForResponse(sendToLog);
if (!response.startsWith("150")){
System.out.println("error during retr");
thrownew IOException("FuriousFTP was not allowed to retrieve the file: "
+ response);
}
ByteArrayOutputStream byteList =new ByteArrayOutputStream();
BufferedOutputStream output =new BufferedOutputStream(byteList);
byte[] buffer =newbyte[4096];
int bytesRead = 0;
while ((bytesRead = input.read(buffer)) != -1){
output.write(buffer, 0, bytesRead);
}
output.flush();
output.close();
input.close();
response = waitForResponse(sendToLog);
if (!response.startsWith("226")){
System.out.println("error after download");
thrownew IOException("FuriousFTP was unable to retrieve the file: "
+ response);
}
File tempFile =new File("/FFTP/Temp/" + fileName);
FileOutputStream fos =new FileOutputStream(tempFile);
fos.write(byteList.toByteArray());
fos.flush();
fos.close();
return tempFile;
}
}
publicvoid clearLog()
{
log ="";
}
// method to wait until the Buffered Reader is ready, then get
// return the first line read as the response string
private String waitForResponse(boolean sendToLog)
throws IOException
{
while(!reader.ready())
{
System.out.println("Waiting for response...");
// THIS IS WHERE IT GETS STUCK!!!
}
String response = readLine(sendToLog);
while(reader.ready())
{
String temp = reader.readLine();
if(sendToLog) addToLog(temp);
}
return response;
}
// returns the log
//************************************************************
public String getLog()
{
return log;
}
// adds one line to the log
//**************************************************************
privatevoid addToLog(String line)
{
log += (line +"\n");
}
}
Message was edited by:
AsSiDuL0Us

