http://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html
I noticed the example disconnects() in the finally clause, but doesn't do the same for logout()
FTPClient ftp = new FTPClient();
FTPClientConfig config = new FTPClientConfig();
config.setXXX(YYY); // change required options
ftp.configure(config );
boolean error = false;
try {
int reply;
ftp.connect("ftp.foobar.com");
System.out.println("Connected to " + server + ".");
System.out.print(ftp.getReplyString());
// After connection attempt, you should check the reply code to verify
// success.
reply = ftp.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
System.err.println("FTP server refused connection.");
System.exit(1);
}
... // transfer files
ftp.logout();
} catch(IOException e) {
error = true;
e.printStackTrace();
} finally {
if(ftp.isConnected()) {
try {
ftp.disconnect();
} catch(IOException ioe) {
// do nothing
}
}
System.exit(error ? 1 : 0);
}
Anyone know why we don't need to logout() when we catch an exception?
Anyone know why we don't need to logout() when we catch an exception?
The inside code of ftp.logout() function is as follows:
public boolean logout() throws IOException
{
return FTPReply.isPositiveCompletion(quit());
}
The quit() function send a command using sendCommand(FTPCommand.QUIT) to the FTP Server. If a connection exception happens, we are likely not being able to connect with FTP Server. calling logout() will try to write to FTP server again and create resources with additional throwing exception. In addition, although disconnect() function will also throw an exception, it closes the input, output, socket and releases resources which logout() function doesn't: as it is evident from the following source code of disconnect() function:
public void disconnect() throws IOException
{
if (_socket_ != null) _socket_.close();
if (_input_ != null) _input_.close();
if (_output_ != null) _output_.close();
if (_socket_ != null) _socket_ = null;
_input_ = null;
_output_ = null;
_controlInput_ = null;
_controlOutput_ = null;
_newReplyString = false;
_replyString = null;
}
I dont know much about the FTPClient library but I believe it's safe to assume disconnecting from the server implies logging out as part of the process if applicable, considering the explanations given in the docs:
disconnect() : Closes the connection to the FTP server and restores connection parameters to the default values.
logout() : Logout of the FTP server by sending the QUIT command.
http://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html
Related
I'm trying to implement no root firewall for android. I've gone through all related questions on SO, but haven't find an answer:
Here I am configuring my vpn.
private void configure() {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("192.168.178.90", 24);
//builder.addAddress("10.0.2.0", 32);
//builder.addDnsServer("8.8.8.8");
builder.addRoute("0.0.0.0", 0); // to intercept packets
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.establish();
}
And then I am trying to send data to destination address
byte[] data= new byte[pdata.data.capacity()];
pdata.data.get(data);
Socket s = new Socket(pdata.destAddr,pdata.destPort);
if(shouldBeBlocked(pdata.destAddr)) {
sendResult("blocked: "+ pdata.destAddr.toString()+":"+pdata.destPort);
} else {
sendResult(pdata.destAddr.toString()+":"+pdata.destPort);
if (protect(s)) {
...
But thread is freezing on constructor of Socket and then rasinig IOException like this:
java.net.ConnectException: failed to connect to /173.194.71.100 (port 443): connect failed: ETIMEDOUT (Connection timed out)
Maybe try builder.setMtu(1492); to be on a safer side. See http://en.wikipedia.org/wiki/Maximum_transmission_unit
I've created Java function that downloads files from FTP server. It works fine from my local machine. But I need to run it under linux server (means another host and port). And the function gives an error
The collection, array, map, iterator, or enumeration portion of a for statement cannot be null
Caused in a line with the code:
for(String f : ftpNames) {
ftpclient.retrieveFile(f, os); // os is OutputStream
}
So it doesn't see the files...
I added
ftpclient.enterRemotePassiveMode();
And ftpclient.getPassiveHost() returns 227 Entering Passive Mode (x,x,x,x,204,15)
Tried to list and download them via shell - it works.
How should I modify my code to solve the problem? Thanks.
UPD. I got log from FTP server I'm trying to get files from, and there is such string:
425 Cannot open data connection
Full code:
static boolean ftpFilesDownload(String ip, int port, String login, String passwd, String ftpdir, String localdir) throws IOException {
Boolean result = false;
FTPClient client = new FTPClient();
String separator = File.separator;
try {
client.connect(ip, port);
System.out.println(client.getReplyString());
client.login(login, passwd);
System.out.println(client.getReplyString());
client.setControlKeepAliveTimeout(1000*60*5);
client.setControlKeepAliveReplyTimeout(1000*60*5);
client.setFileType(FTP.BINARY_FILE_TYPE);
System.out.println("client setFileType success");
client.changeWorkingDirectory(ftpdir);
System.out.println(client.getReplyString());
client.printWorkingDirectory();
System.out.println("directory changed");
FTPFile[] ftpFiles = client.listFiles();
System.out.println(ftpFiles);
String[] ftpNames = client.listNames();
System.out.println("the files are " + Arrays.toString(ftpNames)); // so null here...
for(String f : ftpNames) {
String localfile = localdir + f;
OutputStream os = new FileOutputStream(localfile);
try {
result = client.retrieveFile(f, os);
System.out.println("DOWNLOADING STARTED);
System.out.println(client.getReplyString());
client.noop();
}
catch(Exception e) {
System.out.println(e);
result = false;
}
finally {
if(os != null)
os.close();
}
}
client.logout();
System.out.println(client.getReplyString());
}
catch(Exception e)
{
System.out.println(e);
result = false;
}
finally
{
try
{
client.disconnect();
}
catch(Exception e)
{
System.out.println(e);
result = false;
}
}
return result;
}
As the error message explains, you're trying to iterate over a null object. You should check for this (or make sure an empty Iterable is used perhaps)
If this is an execptional (error) state, I'd check for this explicitly and throw some kind of runtime exception, e.g.:
if (ftpNames == null) {
throw new IllegalArgumentException("Cannot use a null set of FTP servers");
}
for (String f : ftpNames) {
ftpclient.retrieveFile(f, os); // os is OutputStream
}
Alternatively you could try to continue with no FTP servers, but seems a bit pointless.
Try to use ftpclient.enterLocalActiveMode();
EDIT: I have corrected the mistake below in the code, by adding a line into the server code
I'm trying to write some socket code that will allow me to send data from one computer to another for a game (which for simplicity's sake, we can think of as tic-tac-toe, not much data needs to be sent, just a couple of numbers). In order to achieve this I have written two classes, Server and Client. At the moment I am testing through the localhost using port 1234, and I am only using one single instance of the program (though the same problem occurs when trying to use two instances).
Firstly here's the code, and then I can go into more depth about the problem, and what testing I've done to attempt to work out what is going wrong:
public class Server
{
private ServerSocket server;
private Socket socket;
private Client socketHandler;
private static final int DEFAULT_PORT = 1234;
public Server() { this(DEFAULT_PORT); }
public Server(int port)
{
Thread thread = new Thread()
{
public void run()
{
try
{
System.out.println("Attempting to Establish Connection");
server = new ServerSocket(port);
socket = server.accept();
socketHandler = new Client(port, socket); //THIS LINE ADDED
System.out.println("Server Online!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
//ADJUSTED
Client getSocketHandler()
{
return socketHandler;
}
public void kill()
{
try
{
if (socket != null) socket.close();
if (server != null) server.close();
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
socket = null;
server = null;
}
}
}
public class Client
{
public static final int DEFAULT_PORT = 1234;
public static final String DEFAULT_HOST = "localhost";
private static final String THUMP_THUMP = "thump thump";
private static final int PULSE = 1000;
private int port;
private String ip;
private Socket socket;
private BufferedReader input = null;
private PrintWriter output = null;
boolean closed = true;
String data = "";
public Client() { this(DEFAULT_PORT, DEFAULT_HOST, null); }
public Client(int port) { this(port, DEFAULT_HOST, null); }
public Client(int port, String ip) { this(port, ip, null); }
public Client(int port, Socket server) { this(port, DEFAULT_HOST, server); }
public Client(String ip) { this(DEFAULT_PORT, ip, null); }
public Client(String ip, Socket server) { this(DEFAULT_PORT, ip, server); }
public Client(Socket server) { this(DEFAULT_PORT, DEFAULT_HOST, server); }
public Client(int port, String ip, Socket server)
{
socket = server;
this.ip = ip;
this.port = port;
Thread thread = new Thread()
{
public void run()
{
try
{
initialise(server);
String line;
startHeartbeat();
while (isClosed()) {} //first it is closed, lets wait for it to open before we start waiting for it to close!
System.out.println("We are about to listen!");
while (!isClosed())
{
System.out.println("pre-read"); //this line was used to determine that the code was hanging on the next line
line = input.readLine(); //offending line
System.out.println("post-read"); //this line was used to determine when the block was lifted
if (line != null)// || line != THUMP_THUMP)
{
System.out.println(line);
data += line + "\n";
}
}
System.out.println(data);
kill();
System.out.println("Connection Closed!");
}
catch (SocketException e)
{
e.printStackTrace();
System.out.println("Server closed!");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
}
private void initialise(Socket server)
{
try
{
if (server == null) socket = new Socket(ip, port);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
}
catch (IOException e) { e.printStackTrace(); }
}
public boolean post(String text)
{
synchronized(this)
{
output.println(text);
output.flush();
return !output.checkError();
}
}
public void kill()
{
try
{
if (input != null) input.close();
if (socket != null) socket.close();
}
catch(IOException e) { e.printStackTrace(); }
finally
{
input = null;
socket = null;
}
}
public void killOutputStream()
{
try
{
if (output != null) output.close();
}
catch (Exception e) { e.printStackTrace(); }
finally
{
output = null;
}
}
//////////////////////////////////
///////// Socket Control /////////
//////////////////////////////////
synchronized boolean isClosed()
{
return closed;
}
synchronized void setClosed(boolean b)
{
closed = b;
}
//We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
void startHeartbeat()
{
Thread heartbeat = new Thread()
{
public void run()
{
while (output != null)
{
setClosed(post(THUMP_THUMP) ? false : true); //post returns true on success
synchronized(this)
{
try
{
this.wait(PULSE);
}
catch (InterruptedException e) {}
}
}
setClosed(true);
}
};
heartbeat.setDaemon(true);
heartbeat.start();
}
}
The Problem
When the client is started (after having created the server) it fails to read any data sent through (or even the heartbeat), in fact the code does not go past line = input.readLine() in the reading thread (which is from now on called the offending line), except it seems, until the server is disconnected (see below).
Here is the order of regular testing:
Server() is called and the resulting Server is stored in the serverConnection variable then
Client(serverConnection != null ? serverConnection.getSocket() : null) is called and the new Client is stored in clientConnection.
Because we can test whether it is working using the heartbeat no other data needs to be sent, and the server is terminated by calling serverConnection.kill() and then clientConnection.killOutputStream() after letting some time elapse.
and this is the result:
Attempting to Establish Connection Server Online!
We are about to listen!
Connection Closed!
where the empty line represents the non null data received over the course of the connection, ie that there is none.
I expect this:
Attempting to Establish Connection
Server Online!
We are about to listen!
thump thump
thump thump
thump thump (and so on, every second)
Connection closed!
I spent time performing different tests by commenting out or changing the code slightly with the same testing format (except for the special case, which is number 6) and made these observations:
Observations
Only when the socket is closed and the output stream is closed, does the program move past the offending line.
When the readline() method starts to process (shortly before the heartbeat cuts it off) it detects nothing in the stream, not even THUMP_THUMP.
When the socket is closed, but the output stream is not, the readline() method starts to process, only to detect nothing, heartbeat cuts it off. No SocketException even though it would be expected.
If the socket is NOT closed, and only the output stream is closed, a SocketException is triggered, suggesting the socket is closed.
I used netstat -an in command prompt, and when the server is started the port 1234 is LISTENING. When the client connects, it is still LISTENING, implying that there is no connection.
I set up some python code to connect to itself over port 1234,
however I made a mistake in the python code, and as such the server
didn't close, and was still open. So I decided to connect the java
client to the server and see what happens. I did this by running
Client(null) which is the client code for the non-host. It
resulted in the port reading ESTABLISHED, and the python server was
echoing back the "thump thump", and the java code was successfully
reading it. No hanging, it worked perfectly.
This leads me to believe that the problem lies in the server code, as the python server was able to communicate sucessfully with the Java client, but the Java client is unable to communicate with the Java server.
Before performing this testing I had been concentrating on the Client code, believing that it was at fault. All the questions I have found here with similar symptoms (see here, here and here, among others) have turned up blank for me, having written in their solutions (most were due to the output stream not flushing, or the \n ommitted, which I have not failed to do, or the solution not fixing my problem, and so having been removed in favor of the heartbeat in this case). I originally based my code off of this article.
After 4 days of trying to figure out this problem I am at a loss for what to do... What am I missing here? Why is the Server code not working as I expect it to? If anybody needs any more clarification on my code then please ask!
As an after-note, the testing code is run through a simple minimalistic GUI written in javafx (not fxml though), whether that would be a problem or not I'm sure, I would think not, due to it working with the Python server. This code is compiled in Java 8
I'm a little confused about why you think it would go any furthur than input.readLine() considering there is no handling of inputs/outputs on the server side....
Client/Server connections are like a game of tennis, as one side serves the other must receive the ball and then serve it back(maybe with different information). Your server side must handle the input it recieves from the start heartbeat method, and then send you back a response. the input.readLine() function blocks the thread until it receives data from the other end, so yes the code stops there and waits for your server to send the "tennis ball" back. In the server class you should add an input and output stream that handle the heart beat inputs and send back a string of data to the client.
Server:
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
String response = "thump thump";
while(true){
is.read();
os.write(response.getBytes());
os.flush();
}
with this example, the client should remain unchanged and just add the above code to your server.
I made a small application that should upload files to an FTP server. The thing is that I used passive mode with the method
enterLocalPassiveMode()
Recently I was told that no passive mode is allowed on the FTP server, so I should make my application work in active mode. I suppose it couldn't be done by simply changing the method to
enterLocalActiveMode()
What else should I change in the application to ensure it's working in active mode.
Here's a code snippet which makes the connection to the server:
public void connect() throws FTPException {
try {
ftpClient.connect(server, port);
replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
printText("FTP server refused connection.");
throw new FTPException("FTP server refused connection.");
}
boolean logged = ftpClient.login(user, pass);
if (!logged) {
ftpClient.disconnect();
printText("Could not login to the server.");
throw new FTPException("Could not login to the server.");
}
ftpClient.enterLocalPassiveMode();
} catch (IOException ex) {
printText("I/O errortest: " + ex.getMessage());
throw new FTPException("I/O error: " + ex.getMessage());
}
}
Some guidance to what I have to change?
This is old, but I stumbled onto it trying to solve the issue myself.
You have to call enterLocalPassiveMode() after calling connect() and before calling login().
See my example below which initialises the FTPClient in local passive mode, lists files for a given directory, then closes the connections.
private static FTPClient client;
public static void main(String [] args) {
//initialise the client
initPassiveClient();
//do stuff
FTPFile [] files = listFiles("./");
if( files != null ) {
logger.info("Listing Files:");
for( FTPFile f : files) {
logger.info(f.getName());
}
}
//close the client
close();
}
/**
* getPassiveClient retrive a FTPClient object that's set to local passive mode
*
* #return FTPClient
*/
public static FTPClient initPassiveClient() {
if( client == null ) {
logger.info("Getting passive FTP client");
client = new FTPClient();
try {
client.connect(server);
// After connection attempt, you should check the reply code to verify
// success.
int reply = client.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
logger.error("FTP server refused connection.");
System.exit(0);
}
//after connecting to the server set the local passive mode
client.enterLocalPassiveMode();
//send username and password to login to the server
if( !client.login(user, pass) ) {
logger.error("Could not login to FTP Server");
System.exit(0);
}
} catch (SocketException e) {
String message = "Could not form socket";
logger.error(message+"\n", e);
System.exit(0);
} catch (IOException e) {
String message = "Could not connect";
logger.error(message+"\n", e);
System.exit(0);
}
}
return client;
}
public static void close() {
if( client == null ) {
logger.error("Nothing to close, the FTPClient wasn't initialized");
return;
}
//be polite and logout & close the connection before the application finishes
try {
client.logout();
client.disconnect();
} catch (IOException e) {
String message = "Could not logout";
logger.error(message+"\n", e);
}
}
/**
* listFiles uses the FTPClient to retrieve files in the specified directory
*
* #return array of FTPFile objects
*/
private static FTPFile[] listFiles(String dir) {
if( client == null ) {
logger.error("First initialize the FTPClient by calling 'initFTPPassiveClient()'");
return null;
}
try {
logger.debug("Getting file listing for current director");
FTPFile[] files = client.listFiles(dir);
return files;
} catch (IOException e) {
String message = "";
logger.error(message+"\n", e);
}
return null;
}
http://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html#enterLocalActiveMode()
Not sure if this is the FTPClient you're using but it would appear that enterLocalActiveMode does indeed exist.
FTPClient Documentation states that
public boolean enterRemoteActiveMode(InetAddress host,int port)
throws IOException
Set the current data connection mode to ACTIVE_REMOTE_DATA_CONNECTION . Use this method only for server to server data transfers. This method issues a PORT command to the server, indicating the other server and port to which it should connect for data transfers. You must call this method before EVERY server to server transfer attempt. The FTPClient will NOT automatically continue to issue PORT commands. You also must remember to call enterLocalActiveMode() if you wish to return to the normal data connection mode.
Hope this helps!
Very new to Java in particular, using the SimpleFTP library to send a file to a server.
It seems like any method call on a SimpleFTP object seems to require being inclosed in a try-catch. What is the proper way to disconnect from the server, then?
For example:
private void ftp()
{
int portNumber = 21;
SimpleFTP ftp = new SimpleFTP();
try
{
ftp.connect("serverAddress", portNumber, "userName", "password");
ftp.bin();
ftp.cwd("dir");
ftp.stor(new File("filePath"));
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
ftp.disconnect();
}
}
This does not compile, because of the content in fianlly's body. If I move it up to the try block and scrap the finally, it'll compile... But what if my app connects to the server, then throws an exception while doing the other tasks?
What you didn't mention is that the reason you're having a problem is that disconnect() is also declared to throw an IOException.
Looking at the source for SimpleFTP you find:
public synchronized void disconnect() throws IOException {
try {
sendLine("QUIT");
}
finally {
socket = null;
}
}
All it's doing is sending the QUIT command to the remote FTP server then just dropping the reference to the socket in its finally block. If that throws .... it means the socket is already dead, but since you're disconnecting you really don't care (If I'd written that client, i'd have caught and ignored the exception for that reason and not had it throw).
In your finally block just wrap it in it's own try/catch block and don't do anything in the catch block. Option B is just putting it in the try block. The only reason it's going to throw is if the socket is already disconnected and letting the SimpleFTP instance fall out of scope after an exception will clean things up just as well.
Surround the disconnect call with its' own try catch block...
finally
{
if (ftp != null) {
try {
ftp.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}