I've made a basic client server FTP program using sockets, but for some reason files are getting corrupted during the transfer. In the case below, I'm pushing a file to the server from the client. It almost works, since some files (such as a .png) transfer and open fine, but others (a .docx) don't. Any file that I transfer has a different MD5 to the one I sent.
Client code:
File file = null;
FTPDataBlock transferBlock;
int numBytesRead = 0;
int blockNumber = 1;
int blockSize = 1024;
byte[] block = new byte[blockSize];
fc = new JFileChooser();
// select file to upload
int returnVal = fc.showOpenDialog(Client.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
file = fc.getSelectedFile();
try {
// get total number of blocks and send to server
int totalNumBlocks = (int)Math.ceil((file.length()*1.0) / blockSize);
System.out.println("File length is: " + file.length());
FTPCommand c = new FTPCommand("PUSH", Integer.toString(totalNumBlocks));
oos = new ObjectOutputStream(sock.getOutputStream());
oos.writeObject(c);
oos.flush();
// send to server block by block
FileInputStream fin = new FileInputStream(file);
while ((numBytesRead = fin.read(block)) != -1){
transferBlock = new FTPDataBlock(file.getName(), blockNumber, block);
blockNumber++;
System.out.println("Sending block " + transferBlock.getBlockNumber() + " of " + totalNumBlocks);
oos = new ObjectOutputStream(sock.getOutputStream());
oos.writeObject(transferBlock);
oos.flush();
}
fin.close();
System.out.println("PUSH Complete");
// get response from server
ois = new ObjectInputStream(sock.getInputStream());
FTPResponse response = (FTPResponse)ois.readObject();
statusArea.setText(response.getResponse());
} catch (IOException | ClassNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
Server Code:
else if (cmd.getCommand().equals("PUSH")){
// get total number of file blocks
int totalNumBlocks = Integer.parseInt(cmd.getParameters());
// get first block
in = new ObjectInputStream(sock.getInputStream());
FTPDataBlock currentBlock = (FTPDataBlock)in.readObject();
// create file and write first block to file
File file = new File (workingDirectory + File.separator + currentBlock.getFilename());
FileOutputStream fOut = new FileOutputStream(file);
fOut.write(currentBlock.getData());
fOut.flush();
// get remaining blocks
while(currentBlock.getBlockNumber()+1 <= totalNumBlocks){
in = new ObjectInputStream(sock.getInputStream());
currentBlock = (FTPDataBlock)in.readObject();
fOut.write(currentBlock.getData());
fOut.flush();
}
fOut.close();
// send response
FTPResponse response = new FTPResponse("File Received OK");
out = new ObjectOutputStream(sock.getOutputStream());
out.writeObject(response);
}
FTPDataBlock class:
public class FTPDataBlock implements Serializable{
private static final long serialVersionUID = 1L;
private String filename;
private int blockNumber; // current block number
private byte[] data;
//constructors & accessors
}
I'm sure it's something small that I'm missing here. Any ideas?
InputStream.read(byte[])
, in particular what the possible return values might be. (2) Compare the sizes of your input file and your output file. (3) Figure out how #1 and #2 are related. – kdgregoryObjectXStream
s, Use the one you already have. And usewriteUnshared()
rather thanwriteObject()
. – kdgregoryThe number of bytes actually read is returned as an integer
. Hint: it may be smaller than the size of your buffer. – kdgregory