I have a java piece that will FTP a string (long text document) to a remote location. All seems to be working, but I am getting a very long hang time when ftp.storeFile(a,b) is called. This then returns a replyCode 425. It is odd because myData.txt is appearing inside the remote destination, but it is blank. There must be something blocking the input stream? Does anyone know what the issue could be?
Java code:
public void doFTP(){
FTPClient ftp = new FTPClient();
FTPClientConfig config = new FTPClientConfig();
ftp.configure(config);
boolean error = false;
try {
int reply;
String server = "example.com";
ftp.connect(server);
ftp.login(username, password);
reply = ftp.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
}
InputStream is = new ByteArrayInputStream(myString.getBytes()); //String
ftp.setFileType(ftp.BINARY_FILE_TYPE, ftp.BINARY_FILE_TYPE);
ftp.setFileTransferMode(ftp.BINARY_FILE_TYPE);
Boolean test = ftp.storeFile("myData.txt", is); //FTP store here
System.out.println(test);
reply = ftp.getReplyCode();
System.out.println(reply);
is.close();
ftp.logout();
} catch(IOException e) {
// ... not important
} finally {
// ... not important
}
}
The code you are showing looks strange to me. where you have the InputStream is =
this code should be inside the try { ..... } code block.
Found the problem, I need to switch it to:
ftp.enterLocalPassiveMode();
I still don't quite understand why this needs to be done, if anyone could care to explain.
Related
I'm implementing a "little" client/server app, like a Cloud.
The problem is: I'm new to Java.
So I've learned it a bit fast, and same for client/server communication, database, frames, threads.
I'm pretty sure my code won't be the best one, but the fact is: I have to use Java, and I have to do this fast. I won't try to optimize it, I just need it to work.
I have already implemented a lot, so I won't give all the code here, just explain what happens before my problem:
The main prog on client side opens a login frame. The client can register or login. Registration is working well, so let's say he logs in. If authentication works, that opens another frame, with "browse" and "upload" options. The idea is, he browse a file and then upload it. When he clicks on upload, it should call the upload function, which will send a byte[2] array to the server with a DataOutputStream object. (it sends first the size of the array, and then the array)
On the server side, when authentication works, it'll give the client socket to a "Cloud" class, which - until now - is just supposed to receive a byte array (it'll do more later, but for now I can't get this byte array)
But the server receives a size of 1970302063 instead of 2. I've checked the size before the writeInt on client size, it's 2. After the readInt on the server side, it's 1970302063.
I don't understand it. Can the server receive something else somewhere and my beautiful 2 be lost in a buffer?
Server side:
public class Server {
public static void main(String[] zero) throws IOException {
ServerSocket serverSocket ;
Socket clientSocket ;
int tmp = 0; //when everything works, tmp will disappear
DataBase DB = new DataBase();
System.out.println("ouverture du server");
serverSocket = new ServerSocket(2017);
while(tmp<1) { //limit the number of connections allowed.
try {
clientSocket = serverSocket.accept();
Thread t = new Thread(new Connect(clientSocket, DB));
t.start();
//clients.printAll(); //just to see the DB.
}catch (IOException e) {
e.printStackTrace();
}
tmp++;
}
serverSocket.close();
}
}
As you can see, I'm authorising just 1 connection, because I'm still testing it and I don't want to change the port number each time I got an error / change something. With that I'll just have to restart server after each test.
public class Connect implements Runnable{
private DataBase DB;
private Socket clientSocket;
public Connect(Socket socket, DataBase DB) {
this.clientSocket = socket;
this.DB = DB;
}
public void run() {
try {
BufferedReader in;
PrintWriter out;
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out = new PrintWriter(clientSocket.getOutputStream());
String mode = in.readLine();
String clientID = in.readLine();
String clientPwd = in.readLine();
if (mode.equals("auth")) {
Authentification auth = new Authentification (clientID, clientPwd, DB);
out.write(auth.getMessage()+"\r\n");
out.flush();
if (auth.getMessage().equals("Login Successfull. Welcome in SecureCloud!"))
new Cloud(clientSocket, DB); //launch Cloud.
}
else if (mode.equals("reg")) {
Registration reg= new Registration(clientID, clientPwd, DB);
out.write(reg.getMessage()+"\r\n");
out.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
this.clientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now, here: authentication and registration will set up a connection, and the client socket is closed at the end. BUT, if the authentication is successful, then it create a new Cloud:
public class Cloud {
public Cloud(Socket clientSocket, DataBase DB) {
try {
DataInputStream dIn = new DataInputStream(clientSocket.getInputStream());
int length = dIn.readInt(); // read length of incoming message
System.out.println("byte array size: "+length);
byte[] shorthash;
if(length!=2) {
System.err.println("Incorrect size for shorthash!");
}
else {
shorthash = new byte[length];
dIn.readFully(shorthash, 0, shorthash.length); // read the message
System.out.println(shorthash);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
As you can see, for now it doesn't do much. I know I'll have to add a while(true) loop so that the client can upload more files, but for now I'll be happy if I can send just this byte array.
Now, client side. I'll skip the main, it just open the login frame. I'll also skip most of the login Frame, it's just a frame...here is what happens when client click on "login":
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==connectButton) {
Connection con = new Connection();
con.auth(username.getText(), password.getText());
if(con.getServerAnswer().equals("Login Successfull. Welcome in SecureCloud!")) {
this.setVisible(false);
con.setConnection(true);
con.setUsername(username.getText());
new Load_Frame(con.getUsername(),con.getSocket());
}
else System.out.println("erreur: " + con.getServerAnswer());
}
else if (e.getSource()==registerButton) {
this.setVisible(false);
new Registration_Frame();
}
}
So, it creates the connection and launch the authentification process (con.auth) with username and password. If it's successfull, it'll open the Load Frame with the username and socket used for this connection.
I'll skip again most of Load Frame, here are the actions:
public void actionPerformed(ActionEvent e)
{
if (e.getSource()== uploadButton) {
this.filename = uploadField.getText();
File file = new File(filename);
//TODO: change the upload function:
try {
client.upload(file);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else if (e.getSource()== downloadButton) {
this.filename = downloadField.getText();
//TODO: change the download function
//download(filename);
}
else if (e.getSource()== browseButton) {
JFileChooser jc = new JFileChooser();
if(jc.showOpenDialog(this) != 1)
uploadField.setText(jc.getSelectedFile().getAbsolutePath());
}
}
And, last but not least, the "upload" function, called by client.upload(file):
public void upload(File originalFile) throws NoSuchAlgorithmException, NoSuchPaddingException, IOException {
//create the "FileData" object, which make the shorthash of the file.
FileData myfile = new FileData(originalFile, fileID);
//say to the server that we want to upload:
PrintWriter mode;
mode = new PrintWriter(socket.getOutputStream());
mode.println("upload");
mode.flush();
//Send shorthash to the server:
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
System.out.println("byte array size: "+myfile.shortHash.length);
out.writeInt(myfile.shortHash.length); // send the length of the byte array
//out.flush();
out.write(myfile.shortHash); //send the array
}
I've tried with and without the out.flush(), it doesn't make any difference.
With all that, here are the answers I get:
From client:
Asking for authentification...
Login Successfull. Welcome in SecureCloud!
No file uploaded
byte array size: 2
From server:
Connection to SQLite has been established.
ouverture du server
byte array size: 1970302063
Incorrect size for shorthash!
Of course, since I know the size of the byte array, I could easily tell the server "hey, the size is 2!" (I mean, directly initialize my array with new byte[2] )
But I would like to understand what happens here. Plus, if I'm not receiving the good size, maybe I won't receive the good array.
So, thanks to the people who find the problem really fast :)
It was a bit of stupid, the kind of problem you don't see even if you reread your code 5 times, but then someone else read it he see that in a minute.
The solution is to delete this part in the upload function:
//say to the server that we want to upload:
PrintWriter mode;
mode = new PrintWriter(socket.getOutputStream());
mode.println("upload");
mode.flush();
it was usefull until i changed the code on server side, and now it's just annoying ^^
I am trying to store a byteArrayInputStream as File on a FTP Server. I could already connect to the Server and change the working path, but triggering the method to store the Stream as File on the Server returns always false.
I am using the apache FTPClient.
Can someone please give me a hint where my mistake can be!?
Here the Code:
String filename = "xyz.xml"
// connection returns true
connectToFtpServer(ftpHost, ftpUser, ftpPassword, exportDirectory);
// byteArray is not void
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
try {
// change returns true
result = ftpClient.changeWorkingDirectory(exportDirectory);
// storing the file returns false
result = ftpClient.storeFile(filename, byteArrayInputStream);
byteArrayInputStream.close();
ftpClient.logout();
} catch (...) {
...
} finally {
// disconnect returns true
disconnectFromFtpServer();
}
I don't believe it's your code. Here is another example that looks very similar from kodejava:
package org.kodejava.example.commons.net;
import org.apache.commons.net.ftp.FTPClient;
import java.io.FileInputStream;
import java.io.IOException;
public class FileUploadDemo {
public static void main(String[] args) {
FTPClient client = new FTPClient();
FileInputStream fis = null;
try {
client.connect("ftp.domain.com");
client.login("admin", "secret");
//
// Create an InputStream of the file to be uploaded
//
String filename = "Touch.dat";
fis = new FileInputStream(filename);
//
// Store file to server
//
client.storeFile(filename, fis);
client.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I agree it's file permissions. There is not a way to change permissions in java itself yet, but there are other solutions. See this thread: How do i programmatically change file permissions?
HTH,
James
It was actually a permission issue due to an invalid usergroup. After adding my user to the usergroup, i was able to store again files.
I want to implement a FTP Client with Apache Commons Net only for uploading data.
The Connection and Login to FTP-Server works fine.
But the upload does not work right.
The files are a little to big as the originals.
And the files are damaged.
I tried an image, a video and a textfile. Only the textfile is alright.
Now I see while debugging
boolean tmp=client.setFileTransferMode(FTPClient.BINARY_FILE_TYPE);
gives me false. So it can not be set. Why?
(Maybe this is not the problem?)
Here a the rest of my code
client=new FTPClient();
try {
int reply;
client.connect(url, port);
reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply))
{
client.disconnect();
System.err.println("FTP server refused connection.");
System.exit(1);
}
client.login(user, pw);
boolean xxx=client.setFileTransferMode(FTPClient.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(300);
client.enterLocalPassiveMode();
if (client.isConnected())
{
try {
File file=new File(<FILE>);
FileInputStream inputStream = new FileInputStream(file);
OutputStream outputStream = client.storeFileStream(file.getName());
byte[] buffer = new byte[4096];
int l;
while((l = inputStream.read(buffer))!=-1)
{
outputStream.write(buffer, 0, l);
}
inputStream.close();
outputStream.flush();
outputStream.close();}
Change the following:
boolean xxx=client.setFileTransferMode(FTPClient.BINARY_FILE_TYPE);
Should be:
boolean xxx=client.setFileType(FTP.BINARY_FILE_TYPE);
You have confused FileTransferModes with FileTypes.
The available FileTypes are:
FTP.ASCII_FILE_TYPE (default)
FTP.BINARY_FILE_TYPE
FTP.EBCDIC_FILE_TYPE
FTP.LOCAL_FILE_TYPE
The available FileTransferModes are:
FTP.STREAM_TRANSFER_MODE (default)
FTP.BLOCK_TRANSFER_MODE
FTP.COMPRESSED_TRANSFER_MODE
I suppose if apache introduced enums for these constant types, then this kind of problem could be avoided, but then the library would not be available to pre-java-5 runtimes.
I wonder how much of an issue java 1.4 compatibility really is.
If only the text file was transferred successfully, I suspect you need to set the binary transfer file type.
See the setFileType method to see how to do this.
The commons-net wiki mentions this is the cause of most file corruption issues.
This work for me, Uploading Image and download after It´s Ok: Using
FTP.LOCAL_FILE_TYPE
this code using logger, replace for you logger or use System.out.println("");
private void cargarData(File filelocal) {
FTPClient client = new FTPClient();
try {
client.connect("URLHOSTFTP", "PORT: DEFAULT 21");
if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
client.disconnect();
logger.error("FTP server refused connection.");
System.exit(1);
}
client.login("USER FTP", "PASS FTP");
boolean type = client.setFileType(FTP.LOCAL_FILE_TYPE);
logger.info("Tipo Aceptado:" + type);
client.setControlKeepAliveTimeout(300);
client.enterLocalPassiveMode();
if (client.isConnected()) {
FileInputStream fis = null;
fis = new FileInputStream(filelocal);
client.storeFile(filelocal.getName(), fis);
client.logout();
if (fis != null) {
fis.close();
}
}
logger.info(client.getReplyString());
} catch (IOException e) {
logger.error("error" + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
logger.error("error" + e.getMessage());
e.printStackTrace();
}
}
I have the following method to upload_files to an FTP server, I am not receiving any errors yet the file is not appearing on the server after its run. What could be the problem?
public static void upload_files(String un, String pw, String ip, String dir, String fn){
FTPClient client = new FTPClient();
FileInputStream fis = null;
try {
client.connect(ip);
client.login(un, pw);
String filename = dir+"/"+fn;
fis = new FileInputStream(filename);
client.storeFile(filename, fis);
client.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
client.disconnect();
System.out.println("uploaded");
} catch (IOException e) {
e.printStackTrace();
}
}
}
There are a number of possible issues. Assumption is that you are using FTPClient 3.x from Apache commons-net. If using something else, you should probably indicate that in your question. Ideas:
Check the reply status of the connection to make sure you are connecting as expected. There's an example on how to do this in the JavaDoc.
Your filename variable is the path to the local file you want to send. Is that really the same path you want to use for storing the file on the server (relative to the FTP login root)? It might be, but usually isn't. If not, your first parameter to client.storeFile(...) needs to be changed.
Most FTP servers provide ability to log all actions. Are you able to access yours? If so, that usually quickly makes clear what is going wrong.
My code is,
import java.io.*;
import java.net.*;
public class DownloadHttp
{
public static void main(String a[])
{
DownloadHttp d = new DownloadHttp();
String addr = "http://www.gmail.com";
String file = "D:/venkatesh/Software/download1.html";
d.download(addr,file);
}
public void download(String address, String localFileName) {
OutputStream out = null;
URLConnection conn = null;
InputStream in = null;
try {
// Get the URL
URL url = new URL(address);
// Open an output stream to the destination file on our local filesystem
out = new BufferedOutputStream(new FileOutputStream(localFileName));
conn = url.openConnection();
in = conn.getInputStream();
// Get the data
byte[] buffer = new byte[1024];
int numRead;
while ((numRead = in.read(buffer)) != -1) {
out.write(buffer, 0, numRead);
}
// Done! Just clean up and get out
} catch (Exception exception) {
exception.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException ioe) {
// Shouldn't happen, maybe add some logging here if you are not
// fooling around ;)
}
}
}
}
Here I wants download specific file using httpClient using java.
It produces:
"java.net.ConnectException: Connection timed out: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)" as error.
How to resolve it, help me, thanks in advance.
I believe it is a network problem. Have you tried to access the url directly or are you behind a firewall?
Recompiled your code on my machine, it works perfectly well. I'm able to fetch files from the web.
Check if your web-browser can download the file for you (make sure it's not a network problem)
One thing to notice though, in your finally block you might want to close the streams separately. So if anything goes wrong with the input stream, the output stream will still be closed.
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception ignored) {}
try {
if (out != null) {
out.close();
}
} catch (Exception ignored) {}
}
I think you are using a proxy when connecting to internet.
Set these in the code and then retry.
System.setProperty("http.proxyHost", *Proxy-IP*);
System.setProperty("http.proxyPort", *Proxy-Port*);