CipherOutputStream not working - java

I have a problem with the following code.
If I use the ObjectOutputStream everything runs fine but when I try to use the CipherOutputStream I get the following error in the server side.
If I send one file I don't receive it fully.
If I send more than one file the last one to be sended is not received fully but the previous are.
What could it be?
I have seen other posts but they didn't help me.
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:128)
at myCloudServer$myCloudServerThread.run(myCloudServer.java:257)
Client code. Sending a file.
SocketFactory socketFactory = SSLSocketFactory.getDefault();
clientSocket = socketFactory.createSocket(serverAddress[0], Integer.parseInt(serverAddress[1]));
ObjectInputStream objectInputStream = new ObjectInputStream(clientSocket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream());
[...]
byte[] buffer = new byte[1024];
objectOutputStream.writeObject(sendingClientFiles.size());
for (File sendingClientFile : sendingClientFiles) {
[...]
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKeyEncrypt = keyGenerator.generateKey();
Cipher cipherEncrypt = Cipher.getInstance("AES");
cipherEncrypt.init(Cipher.ENCRYPT_MODE, secretKeyEncrypt);
CipherOutputStream cipherOutputStream = new CipherOutputStream(objectOutputStream, cipherEncrypt);
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(sendingClientFile));
int count = 0;
while ((count = bufferedInputStream.read(buffer, 0, buffer.length)) != -1) {
//objectOutputStream.write(buffer, 0, count);
cipherOutputStream.write(buffer, 0, count);
}
bufferedInputStream.close();
//objectOutputStream.flush();
cipherOutputStream.flush();
}
Server code. Receiving a file.
ServerSocketFactory serverSocketFactory = SSLServerSocketFactory.getDefault();
serverSocket = serverSocketFactory.createServerSocket(port);
Socket clientSocket = serverSocket.accept();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(clientSocket.getInputStream());
[...]
byte[] buffer = new byte[1024];
int i = 0;
int receivingClientFiles = (int) objectInputStream.readObject();
while(i < receivingClientFiles) {
[...]
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(diretorio + "/" + fileName));
int count = 0;
int received = 0;
while (received < fileLength) {
count = objectInputStream.read(buffer, 0, buffer.length);
bufferedOutputStream.write(buffer, 0, count);
received += count;
}
//while ((count = objectInputStream.read(buffer, 0, buffer.length)) != -1) {
// bufferedOutputStream.write(buffer, 0, count);
//}
bufferedOutputStream.close();
i++;
}

In count = objectInputStream.read(buffer, 0, buffer.length); you should max out on the file size (because you may otherwise read bytes from the next file). And that particular file size must be the encrypted length of the stream, not the original file size (if they differ, that is).

Related

How to read Socket InputStream for multiple files over byte[] streams?

The code I have posted below works for single file transfer over a socket. But it doesn't work for multiple file transfers over a socket. When trying multiple file transfers over the socket the code crashes.
I send multiple files by looping over the server sending code x amount of times, and run the receiving code x amount of times. When trying to send multiple files, the first file will send successfully, the second file name and size will be read successfully but the error in my code happens after this.
In my receiving client I tried to use to suggestion posted here: Java multiple file transfer over socket but had no success.
The error is on the client side.
The question I am asking is: Why isn't this code working for multiple files, and how can I fix it?
Server Sending
try{
byte[] bytes = new byte[(int)file.length()];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
out.println(file.getName()); // Send Filename
out.println(file.length()); // Send filesize
int count;
while ((count = fis.read(bytes)) > 0) {
os.write(bytes, 0, count);
}
os.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client Recieving
try{
String file = in.readLine(); // Read filename
int fileSize = Integer.parseInt(in.readLine()); // Read Filesize
//ERROR HAPPENING ON LINE ABOVE IN LOOPS AFTER THE FIRST
byte [] buf = new byte [fileSize];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
int count = 0;
while (fileSize > 0 && (count = is.read(buf, 0, (int)Math.min(buf.length, fileSize))) != -1){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
The error is a NumberFormatException, on loops after the first when the client is receiving part of a file for the input to the fileSize.
Make sure you flush the PrintWriter before you then write raw bytes directly to the OutputStream that the PrintWriter is attached to. Otherwise, you could write any buffer data out of order to the underlying socket.
But more importantly, make sure that if you use buffered reading on the receiving end that you read the file bytes using the same buffer that receives the file name and file size. You should also transfer the File using smaller fixed chunks, don't allocate a single byte[] array for the entire file size, that is a waste of memory for large files, and likely to fail.
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.println(file.length()); // Send filesize
pw.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
long fileSize = Long.parseLong(isr.readLine()); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
That being said, you might also consider using DataOutputStream.writeLong() and DataInputStream.readLong() to send/receive the file size in its original binary format instead of as a textual string:
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.flush();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(file.length()); // Send filesize
dos.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
DataInputStream dis = new DataInputStream(bos);
long fileSize = dis.readLong(); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}

Send a video file from client to server and back

What I basically want is a simple video file transfer: when I press a button the client will send the file to the server and then the server sends the file back again to the client.
What I got now is just send from client to server and server receives it.
Here's some code to begin with :
Client :
System.out.println("Connecting...");
sock = new Socket(IP, PORT);
InputStream is = new FileInputStream(new File("FILE PATH"));
byte[] bytes = new byte[1024];
OutputStream stream = sock.getOutputStream();
int count = is.read(bytes, 0, 1024);
while (count != -1) {
stream.write(bytes, 0, 1024);
count = is.read(bytes, 0, 1024);
}
is.close();
stream.close();
sock.close();
System.out.println("2");
Server:
byte[] data = new byte[1024];
int count = fin.getInputStream().read(data, 0, 1024);
System.out.println("Receiving video...");
File video = new File("test.mp4");
FileOutputStream fos = new FileOutputStream(video);
while (count != -1) {
fos.write(data, 0, count);
count = fin.getInputStream().read(data, 0, 1024);
}
fos.close();
fin.close();
System.out.println("Done receiving");
Thanks.

Data loss while sending image over socket from android client to Java server

I'm trying to send my image from android client to Java server. Size of image that i'm sending is about 99kb, but server always reads a few kb less, sometimes 98, sometimes 96 and so on. I'd like to know why that data is lost and how can I send image in a proper way. Please help :)
Code:
Client(sending image):
public void sendImage(File file){
try {
out = new PrintWriter(socket.getOutputStream(),true);
out.println("Image");
out.println(file.length());
byte[] byteArray = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(byteArray,0,byteArray.length);
OutputStream os = socket.getOutputStream();
FilterOutputStream bos = new FilterOutputStream(os);
bos.write(byteArray,0,byteArray.length);
bos.flush();
os.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server(receiving image):
if(input.equals("Image")){
input = in.readLine();
int fileSize = Integer.parseInt(input);
System.out.println("FILESIZE:" +fileSize);
byte[] byteArray = new byte[fileSize];
FileOutputStream fileOutputStream =
new FileOutputStream("filename.jpg");
BufferedOutputStream bos =
new BufferedOutputStream(fileOutputStream);
BufferedInputStream bis = new BufferedInputStream(in_);
int bytesRead = bis.read(byteArray, 0, byteArray.length);
int current = bytesRead;
do {
bytesRead = bis.read(byteArray, current,
(byteArray.length - current));
if (bytesRead >= 0) {
current += bytesRead;
System.out.println(current);
}
} while (bytesRead != -1);
bos.write(byteArray, 0, current);
bos.flush();
bos.close();
}
EDIT
Problem solved, working code is as follows:
Client side:
public void sendImage(File file){
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I');
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server side:
if(input =='I'){
DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
long length = dis.readLong();
File to = new File("filename.jpg");
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len, current = 0;
System.out.println(length);
while ( current != length) {
len = dis.read(buffer);
dos.write(buffer, 0, len);
current += len;
System.out.println(current);
}
dis.close();
dos.close();
}
From my personal experience PrintWriter and Buffers dont work well together..
As buffers trying to read data before you tell it to it can "steal" data that it should not do. For example if you use any kind of buffered reader to read the input on the server side that buffer will steal some parts at the "start" of the incomming image becuase it think's it's just another line. You could always try using DataInputStream and DataOutputStream instead..
Client:
public void sendImage(File file) {
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I'); // as image,
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server:
// assuming folder structure exists.
public void readImage(Socket s, File to) throws IOException {
DataInputStream dis = new DataInputStream(s.getInputStream());
char c = dis.readChar();
if (c == 'I') {
long length = dis.readLong();
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len;
while ((len = dis.read(buffer)) != -1) {
dos.write(buffer, 0, len);
}
dis.close();
dos.close();
}
}
As a starting point, in the client side, you will also need a loop for reading the local image, because are you sure that...
bis.read(byteArray,0,byteArray.length);
... is really reading the whole image? So you will also need a loop as in the server side.

File download from PC to Android device - OutputStream write( ) stucks for large files

I'm trying to download a file from PC to Android device (emulator or physical)
Everything goes fine for small and medium sized files, but when I try to send something larger than say 10Mb, server never reaches this statement out2.println("ready");, hence the client hangs waiting for "ready" from server
Seems that server stucks at this: os.write(bytearray, 0, bytearray.length);
So far I've tried this on emulator, I'm going to report about results on a real device shortly
Here is my client part, in Android app: Android client sends "download" string to server, then receives "ready" reply from it, and starts reading file from InputStream
int filesize = 2022386;
int bytesRead;
int currentTot = 0;
Socket socket1 = new Socket("172.16.6.119", 50001); //data line
Socket socket2 = new Socket("172.16.6.119", 50001); //control line
BufferedReader in2 = new BufferedReader(new InputStreamReader(socket2.getInputStream()));
PrintWriter out2 = new PrintWriter(socket2.getOutputStream(), true);
out2.println("download:"); //control line
String usrtxt = in2.readLine();
if(usrtxt.substring(0,5).equals("ready")) //control line
{
byte [] bytearray = new byte [filesize];
InputStream is = socket1.getInputStream(); //data line
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory().toString() + "/sunset.jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(bytearray,0,bytearray.length);
currentTot = bytesRead;
Log.e("DOWNLOAD", "init value: bytesread = " + Integer.toString(bytesRead));
do {
bytesRead =
is.read(bytearray, currentTot, (bytearray.length-currentTot)); //<--does not pull data (WHY?)
Log.e("DOWNLOAD", "bytesread = " + Integer.toString(bytesRead));
if(bytesRead >= 0) currentTot += bytesRead;
} while(bytesRead > -1);
out1.println("finished:");
bos.write(bytearray, 0 , currentTot);
Log.e("DOWNLOAD", Integer.toString(currentTot));
bos.flush();
bos.close();
socket1.close(); socket2.close();
}
And this is my server code: it accepts connection from client, then receives "download" string from it, replies with "ready", and puts the file onto OutputStream
while (true) {
final Socket socket = serverSocket.accept(); //data line
final Socket socket2= serverSocket.accept(); //control line
BufferedReader in2 = new BufferedReader(new InputStreamReader(socket2.getInputStream()));
PrintWriter out2 = new PrintWriter(socket2.getOutputStream(), true);
String usrtxt = in2.readLine(); //control line
if(usrtxt.substring(0,8).equals("download"))
{
System.out.println("accepted download request. sending file");
File transferFile = new File("sunset.jpg");
byte[] bytearray = new byte[(int)transferFile.length()];
FileInputStream fin = new FileInputStream(transferFile);
BufferedInputStream bin = new BufferedInputStream(fin);
bin.read(bytearray, 0, bytearray.length);
OutputStream os = socket.getOutputStream();
os.write(bytearray, 0, bytearray.length); //data line
os.flush();
os.close();
out2.println("ready"); //control line
socket.close(); socket2.close();
bin.close(); fin.close();
System.out.println("file transfer complete");
}//end if
}//end while
This is no way to copy streams. It assumes too many things that may not be true.
The canonical way in Java is as follows:
byte[] buffer = new byte[8192]; // or whatever you like, anything above zero. Note that it doesn't have to be the size of the file
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
If you know the length in advance and you want to keep the socket open afterwards, keep track of the bytes transferred so far via 'total += count;' after the read call inside the loop, and change the read call to read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total)).

java send file using sockets

I am trying to send a file from one computer to another using Java. I have written the code below, it works fine if both sender and receiver are started in the same computer but if they work on different machines received file size is bigger than the original file and it is corrupted.
Note: I am trying to transfer files which are max 10 MBs.
How can I fix this?
Sender:
ServerSocket server_socket = new ServerSocket(8989);
File myFile = new File(myPath);
Socket socket = server_socket.accept();
int count;
byte[] buffer = new byte[1024];
OutputStream out = socket.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(myFile));
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
out.flush();
}
socket.close();
Receiver:
Socket socket = new Socket(address, 8989);
FileOutputStream fos = new FileOutputStream(anotherPath);
BufferedOutputStream out = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int count;
InputStream in = socket.getInputStream();
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
fos.close();
socket.close();
On the client side you write up to count bytes and send them:
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
on the server side you read up to count bytes - but then you write the whole buffer to file!
while((count=in.read(buffer)) > 0){
fos.write(buffer);
Just change it to:
fos.write(buffer, 0, count);
and you'll be on the safe side. BTW your program has another small bug: read() can return 0 which doesn't mean InputStream ended. Use >= instead:
count = in.read(buffer)) >= 0
Have you considered IOUtils.copy(InputStream, OutputStream) from Apache Commons? It would reduce your whole while loops to:
OutputStream out = socket.getOutputStream();
InputStream in = new FileInputStream(myFile);
IOUtils.copy(in, out);
socket.close();
Less code to write, less code to test. And buffering is done internally.
Remember that in.read(buffer) not necessarily fills up the whole buffer with new data. Therefore you should make sure you don't write the whole buffer. Change
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
to
while((count=in.read(buffer)) >0){
fos.write(buffer, 0, count);
}
sender
Socket sock = new Socket("127.0.0.1", 5991);
System.out.println("Connecting.........");
File myFile = new File("/root/qrcode/");
File[] files = myFile.listFiles();
OutputStream os = sock.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(files.length);
long totalBytesRead = 0;
int percentCompleted = 0;
for(File file : files)
{
long length = file.length();
dos.writeLong(length);
String name = file.getName();
dos.writeUTF(name);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int theByte = 0;
while((theByte = bis.read()) != -1)
{
totalBytesRead += theByte;
bos.write(theByte);
}
// System.out.println("file read");
bis.close();
}
dos.close();
//Closing socket
sock.close();
receiver
ServerSocket serverSocket = new ServerSocket(5991);
while(true) {
Socket clientSocket = null;
System.out.println("Starting...");
clientSocket = serverSocket.accept();
InputStream in = clientSocket.getInputStream(); //used
BufferedInputStream bis = new BufferedInputStream(in);
String dirPath ;
dirPath = "/root/NewFolder";
try{
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
File[] files = new File[filesCount];
long f_l = 0;
int count =0 ;
long totalBytesRead = 0;
int percentCompleted = 0;
for(int i = 0; i < filesCount; i++)
{
long fileLength = dis.readLong();
String fileName = dis.readUTF();
f_l = f_l +fileLength;
files[i] = new File(dirPath + "/" + fileName);
FileOutputStream fos = new FileOutputStream(files[i]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int tot = 0;
for(int j = 0; j < fileLength; j++) {
bos.write(bis.read());
}
bos.close();
}
}catch(Exception ex)
{
System.out.println("error in socket programming ");
}
}

Categories

Resources