Java file transfer client not reading all bytes [duplicate] - java

This question already has answers here:
Java multiple file transfer over socket
(3 answers)
Closed 7 years ago.
I have a file sender and receiver. From the 10 or so posts I've found on the internet, this is the correct way to send files through sockets in Java. Take a look at the code snippets below.
Sender:
OutputStream bos = clientSocket.getOutputStream();
FileInputStream fis = new FileInputStream(sendingFile);
BufferedInputStream bis = new BufferedInputStream(fis);
int n;
int total = 0;
byte[] buffer = new byte[8192];
while ((n = bis.read(buffer)) > 0) {
bos.write(buffer, 0, n);
System.out.println("Sending File... ");
total += n;
System.out.println(total);
}
Receiver:
InputStream bis = clientSocket.getInputStream();
FileOutputStream fos = new FileOutputStream(fileOut);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int n;
int total = 0;
byte[] buffer = new byte[8192];
while ((n = bis.read(buffer)) > -1) {
bos.write(buffer, 0, buffer.length);
System.out.println("Writing File... ");
total += n;
System.out.println(total);
if (total == fileSize) {
break;
}
}
System.out.println("File Received");
Here's the output from the Sender
Sending File: D:\Users\Administrator\Documents\AAAAAAAAAAAAAAAAAAAAAAAAAAA.avi
File Size: 54236160
Sending File...
8192
Sending File...
16384
....................some time later
Sending File...
54231040
Sending File...
54236160
File Sent
The last number, 54236160, is the exact size of the file being sent. Now here is the last line on the receiver side.
Writing file...
54234710
So for this particular file, it always stops at this size and so because the entire file isn't sent, the receiver never stops waiting for data. I dont understand how the sender is sending the correct amount of data but the receiver doesn't get it all. I never see "File Received" on the receiver side and the amount of data that the receiver reads is never equal to the amount being sent.
This issue occurs for any file I sent and if I send really small files, such as those that are in bytes not kb, I dont see any "Writing File..." on the receiver side at all, almost like it just ignores the stream.
Yet every post on the internet says this is the proper way to send files. Oh and if I close the sending socket and/or stream, which I dont want to do because there are other things the client and server need to do, it still doesnt fix the problem anyway.
The other thing I've noticed is that while the sender always seems to indicate its writing the full amount to the buffer (always multiples of 8192 for "total"), the receiver doesnt.
Below is the code that gets the filesize and filename. Perhaps this is where the error lies? I dont see how since its all done before we start sending and receiving the file.
System.out.println("Receiving File");
try {
clientScanner.nextLine();
String fileName = clientScanner.nextLine();
int fileSize = clientScanner.nextInt();
System.out.println("File: " + fileName + " Size: " + fileSize);
File fileOut = new File("C:\\Users\\owner\\AppData\\Local\\temp\\" + fileName);
InputStream bis = clientSocket.getInputStream();
FileOutputStream fos = new FileOutputStream(fileOut);
BufferedOutputStream bos = new BufferedOutputStream(fos);

You shouldn't try to read more data than expected. Your loop should be:
int n;
int bytesLeft = fileSize;
byte[] buffer = new byte[8192];
while (bytesLeft > 0) {
int n = bis.read(buffer, 0, Math.min(buffer.length, bytesLeft));
if (n < 0) {
throw new EOFException("Expected " + bytesLeft + " more bytes to read");
}
bos.write(buffer, 0, n);
System.out.println("Writing File... ");
bytesLeft -= n;
System.out.println(total " bytes left to read");
}
(You can adjust the output to show how many bytes you've read instead of how many you've got left to read if you want, but I think this approach is simpler.)
If that still doesn't get you all the data, you should flush the output stream in the writing code - I wouldn't expect you'd have to, but if you're not closing the socket, I guess it could be buffering it forever.
If the loop terminates but the file appears to be incomplete, make sure you're closing bos after all of this.
If none of that helps, then it's possible that something else has read the start of your data before you get into this loop. You should compare the data in the output file with the original file. Look at the first (say) 16 bytes in the output file, and check that they're at the start of the input file. If they're not, then that suggests that the problem is with what you're doing with the connection before the code you've shown us. (For example, the code used to send and receive the expected file size.)
Now that we can see how you're sending / receiving the file size, that's definitely the problem. The scanner is reading some of the file data. To fix this, just use DataOutputStream on the sending side and DataInputStream on the receiving side:
DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream());
output.writeUTF(fileName);
output.writeInt(fileSize);
// Write the data as before, to output
On the receiving side:
DataInputStream input = new DataOutputStream(clientSocket.getInputStream());
String fileName = input.readUTF(name);
int fileSize = input.readInt();
// Read the data before, as above, from input

Related

Server and Client sending file Java [duplicate]

This question already has answers here:
Java multiple file transfer over socket
(3 answers)
Closed 5 years ago.
I am writing a program that has a client and server where the client will send a img file to the server. The code below is for the server where it will get stuck on that while loop from obIn.read blocking on its last run, so it never is able to return -1 and break the loop. It does break the loop for my Client. So I tried to flush it after the loop on the Client but it doesn't seem to do any good. I don't want to close obOut because that will in return close the socket which I want to keep open. The server end is where it receives the bites from the obIn(inputstream that is an instance variable) and writes it to a file that I have created.
//server receives file
File file = new File("image/image.png");
BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream(file));
byte[] bytes = new byte[1000];
int c = 0;
while((c = obIn.read(bytes)) != -1) {
fileOut.write(bytes, 0, c);
fileOut.flush();
System.out.println(c);
}
System.out.println(c);
fileOut.close();
System.out.println("File Created");
//Client
String imgPath = in.nextLine();
File file = new File(imgPath);
BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream(file));
byte[] bytes = new byte[1000];
int c = 0;
while((c = fileIn.read(bytes)) != -1) {
obOut.write(bytes, 0, c);
obOut.flush();
System.out.println(c);
}
obOut.write(bytes, 0, 1000);
obOut.flush();
System.out.println(c);
fileIn.close();
System.out.println("File Sent");
This image is the output where the server is on top and the client is on bottom. That is where I found that the Server is stuck blocking.
Here is where I found this method and tried making it work for my setup. This is my first time working with streams.
In your client class try replacing write and flush function out side of while loop with obOut.close();

Send and then receive file in the same socket? [Java] [duplicate]

I am sending files to remote Android client from java server. I write the bytes using outputstream. On reading these bytes read() method keep trying to read bytes after the stream is ended. if I close the outputstream on server-side, read operation work fines. But I have to write file on the same socket again so can't close output stream any solution?
NOTE: MY CODE WORKS FINE FOR SHARING SINGLE FILE
CODE FOR WRITING FILE
public static void writefile(String IP, String filepath, int port, OutputStream out) throws IOException {
ByteFileConversion bfc = new ByteFileConversion();
byte[] file = bfc.FileToByteConversion(filepath);
out.write(file, 0, file.length);
out.close(); // i donot want to close this and how can I tell reading side that stream is ended.
System.out.println("WRITTEN");
}
Here Am I reading the file on Android :
public Bitmap fileReceived(InputStream is) {
Bitmap bitmap = null;
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "a.png";
String imageInSD = baseDir + File.separator + fileName;
// System.out.println(imageInSD);
if (is != null) {
FileOutputStream fos = null;
OutputStream bos = null;
try {
bos = new FileOutputStream(imageInSD);
byte[] aByte = new byte[1024];
int bytesRead;
int index = 0;
DataInputStream dis = new DataInputStream(is);
while ((bytesRead = is.read(aByte)) > 0) {
index = bytesRead + index;
bos.write(aByte, 0, bytesRead);
// index = index+ bytesRead;
System.out.println("Loop" + aByte + " byte read are " + bytesRead + "whree index =" + index);
}
bos.flush();
bos.close();
Log.i("IMSERVICE", "out of loop");
java.io.FileInputStream in = new FileInputStream(imageInSD);
bitmap = BitmapFactory.decodeStream(in);
bitmap = BitmapFactory.decodeFile(imageInSD);
Log.i("IMSERVICE", "saved");
// if (bitmap != null)
// System.out.println("bitmap is "+ bitmap.toString());
} catch (IOException ex) {
// Do exception handling
// Log.i("IMSERVICE", "exception ");
System.out.println("ex");
}
}
return bitmap;
}
Actually, I want to reset socket connection
Thanks in advance
You need to:
Send the length of the file ahead of the file. You can use DataOutputStream.writeLong() for that, and DataInputStream.readLong() at the receiver.
Read exactly that many bytes from the stream at the receiver:
while (total < length && (count = in.read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total))) > 0)
{
out.write(buffer, 0, count);
total += count;
}
E&OE
Actually I want to reset socket connection
Actually you don't want to do any such thing.
If i donot close outputstream the read operation on other side stuck on keep reading
That is because the client socket's InputStream is still waiting for the server to send some packets of data thus blocking your Main Thread.
Solution:
You can put each of your sending(OutputStream) and reading(InputStream) of packets of data from the socket to a Thread to prevent blocking your main thread when reading and sending.
Create a thread that reads the InputStream and another one for the OutputStream
Side note:
Don't try to close your outputStream that it cant be reopened again as the documentation is saying:
Closing the returned OutputStream will close the associated socket.
The general contract of close is that it closes the output stream. A closed stream cannot perform output operations and cannot be reopened.

java socket programming to send and receive file between two machines

I am trying to communicate between two machines using socket programming.
What I basically need is both machines should be able to send and receive files. The code I am pasting below is not showing any error but the server side program seems to be running indefinitely, i.e., it is not terminating. It got stuck on the line marked with comment stuck here.
In this code, initially, server is sending the file named "file.txt" and client is receiving it and saving the file with name "copy.txt". Later client is sending a file named "file2.txt" and server is receiving and saving it with name "copy2.txt".
Can someone please tell me the error and suggest some improvements?
//server side code
import java.net.*;
import java.io.*;
public class server
{
public static void main (String [] args ) throws IOException
{
//sending file started
ServerSocket serverSocket = new ServerSocket(16167);
Socket socket = serverSocket.accept();
System.out.println("Accepted connection : " + socket);
File transferFile = new File ("/Users/abhishek/desktop/file.txt");
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();
System.out.println("Sending Files...");
os.write(bytearray,0,bytearray.length);
os.flush();
System.out.println("File transfer complete");
//socket.close();
//sending comleted
//receiving file started
int filesize=1022386;
int bytesRead=0;
int currentTot = 0;
byte [] bytearray1 = new byte [filesize];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("/Users/abhishek/desktop/copy2.txt");
//fos.flush();
BufferedOutputStream bos = new BufferedOutputStream(fos);
//bos.flush();
System.out.println("not moving ahead!!!");//program stucked here
bytesRead = is.read(bytearray1,0,bytearray1.length);
currentTot = bytesRead;
System.out.println("current"+currentTot);
do
{
bytesRead = is.read(bytearray1, currentTot, (bytearray1.length-currentTot));
if(bytesRead >= 0)
currentTot += bytesRead;
System.out.println("current"+currentTot);
} while(bytesRead > -1);
System.out.println("outside current"+currentTot);
bos.write(bytearray1, 0 , currentTot);
bos.flush();
//receiving complete
System.out.println("Receving file completed");
socket.close();
}
}
//client side code
import java.net.*;
import java.io.*;
public class client
{
public static void main (String [] args ) throws IOException
{
int filesize=1022386;
int bytesRead=0;
int currentTot = 0;
Socket socket = new Socket("localhost",16167);
byte [] bytearray = new byte [filesize];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("/Users/abhishek/desktop/copy.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(bytearray,0,bytearray.length);
currentTot = bytesRead;
do
{
bytesRead = is.read(bytearray, currentTot, (bytearray.length-currentTot));
if(bytesRead >= 0)
currentTot += bytesRead;
} while(bytesRead > -1);
System.out.println("current"+currentTot);
bos.write(bytearray, 0 , currentTot);
bos.flush();
bos.close();
System.out.println("receiving first file completed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
//sending file
System.out.println("sending second file started!");
File transferFile = new File ("/Users/abhishek/desktop/file2.txt");
byte [] bytearray2 = new byte [(int)transferFile.length()];
FileInputStream fin = new FileInputStream(transferFile);
BufferedInputStream bin = new BufferedInputStream(fin);
bin.read(bytearray2,0,bytearray2.length);
OutputStream os = socket.getOutputStream();
os.flush();
os.write(bytearray2,0,bytearray2.length);
os.flush();
System.out.println("sending second file completed!");
//sending complete
socket.close();
}
}
Does the System.out.println("not moving ahead!!!");//program stucked here line actually execute? if so, then the problem is that the InputStream.read() functions are blobking functions; they will stop execution of the program ("block") until they are able to complete.
From the JavaDoc for InputStream:
Reads up to len bytes of data from the input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read. The number of bytes actually read is returned as an integer.
This method blocks until input data is available, end of file is detected, or an exception is thrown.
Since you aren't getting an exception, this means that when you call .read(), there is no data available to be read, and you program sits around waiting for data to read (that never arrives). You should check that your client program is actually sending the data in the first place.
I'd bet
bytesRead = is.read(bytearray1,0,bytearray1.length);
is where you're really getting stuck. The problem normally if you are stuck here is that the other side of the communication has not sent any data, there's nothing to read, and your thread is stuck waiting for it to send.
on your client side, you call
bos.close();
after sending the first message. This is going to cause the socket to close as well, which will throw an IOException on your server end, and because you are not catching the IOException, your server program will just exit.
How much socket experience do you have? If you are just beginning with sockets, you might want to check out the extensions I wrote around this, starting with ServerSocketEx and DataFetcher.

how to send both binary file and text using the same socket

i have to send a short string as text from client to server and then after that send a binary file.
how would I send both binary file and the string using the same socket connection?
the server is a java desktop application and the client is an Android tablet. i have already set it up to send text messages between the client and server in both directions. i have not yet done the binary file sending part.
one idea is to set up two separate servers running at the same time. I think this is possible if i use two different port numbers and set up the servers on two different threads in the application. and i would have to set up two concurrent clients running on two services in the Android app.
the other idea is to somehow use an if else statement to determine which of the two types of files is being sent, either text of binary, and use the appropriate method to receive the file for the file type being sent.
example code for sending text
PrintWriter out;
BufferedReader in;
out = new PrintWriter(new BufferedWriter
(new OutputStreamWriter(Socket.getOutputStream())) true,);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println("test out");
String message = in.readLine();
example code for sending binary file
BufferedOutputStream out;
BufferedInputStream in;
byte[] buffer = new byte[];
int length = 0;
out = new BufferedOutputStream(new FileOutputStream("test.pdf));
in = new BufferedInputStream(new FileOutputStream("replacement.pdf"));
while((length = in.read(buffer)) > 0 ){
out.write(buffer, 0, length);
}
I don't think using two threads would be necessary in your case. Simply use the socket's InputStream and OutputStream in order to send binary data after you have sent your text messages.
Server Code
OutputStream stream = socket.getOutputStream();
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(stream)
)
);
out.println("test output");
out.flush(); // ensure that the string is not buffered by the BufferedWriter
byte[] data = getBinaryDataSomehow();
stream.write(data);
Client Code
InputStream stream = socket.getInputStream();
String message = readLineFrom(stream);
int dataSize = getSizeOfBinaryDataSomehow();
int totalBytesRead = 0;
byte[] data = new byte[dataSize];
while (totalBytesRead < dataSize) {
int bytesRemaining = dataSize - totalBytesRead;
int bytesRead = stream.read(data, totalBytesRead, bytesRemaining);
if (bytesRead == -1) {
return; // socket has been closed
}
totalBytesRead += bytesRead;
}
In order to determine the correct dataSize on the client side you have to transmit the size of the binary block somehow. You could send it as a String right before out.flush() in the Server Code or make it part of your binary data. In the latter case the first four or eight bytes could hold the actual length of the binary data in bytes.
Hope this helps.
Edit
As #EJP correctly pointed out, using a BufferedReader on the client side will probably result in corrupted or missing binary data because the BufferedReader "steals" some bytes from the binary data to fill its buffer. Instead you should read the string data yourself and either look for a delimiter or have the length of the string data transmitted by some other means.
/* Reads all bytes from the specified stream until it finds a line feed character (\n).
* For simplicity's sake I'm reading one character at a time.
* It might be better to use a PushbackInputStream, read more bytes at
* once, and push the surplus bytes back into the stream...
*/
private static String readLineFrom(InputStream stream) throws IOException {
InputStreamReader reader = new InputStreamReader(stream);
StringBuffer buffer = new StringBuffer();
for (int character = reader.read(); character != -1; character = reader.read()) {
if (character == '\n')
break;
buffer.append((char)character);
}
return buffer.toString();
}
You can read about how HTTP protocol works which essentially sends 'ascii and human readable' headers (so to speak) and after that any content can be added with appropriate encoding like base64 for example. You may create sth similar yourself.
You need to first send the String, then the size of the byte array then the byte array, use String.startsWith() method to check what is being send.

Socket: premature end of JPEG file

I'm trying to send an image file from a server to a client via a socket. The socket was previously used to send some strings from the server to the client (with buffered input/output streams).
The trouble is the image file can't be received properly, with "Premature end of JPEG file" error.
The server first sends the file size to the client, the client then creates a byte[] of that size, and starts to receive the file.
Here are the codes:
Server:
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
//Send file size
dos.writeInt((int) file.length());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
byte[] fileBytes = new byte[bis.available()];
bis.read(fileBytes);
bis.close();
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(fileBytes);
bos.flush();
Client:
DataInputStream dis = new DataInputStream(socket.getInputStream());
//Receive file size
int size = dis.readInt();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] fileBytes = new byte[size];
bis.read(fileBytes, 0, fileBytes.length);
More interestingly, if I let server sleep for about 2 seconds between sending the file size and writing the byte[], then the image is received properly. I wonder if there's some kind of race condition between the server and the client
The error is most likely here:
byte[] fileBytes = new byte[bis.available()];
The method available does not return the size of the file. It might return only the size of the input buffer, which is smaller than the size of the file. See the API documentation of the method in BufferedInputStream.
Also, read in the line below is not guaranteed to read the whole file in one go. It returns the number of bytes that were actually read, which can be less than what you asked for. And in the client code, you are using read in the same way, without actually checking if it read all the data.
Please check commons-io with FileUtils and IOUtils. This should make work a lot easier.
http://commons.apache.org/io/
The correct way to copy a stream in Java is as follows:
int count;
byte[] buffer = new byte[8192]; // more if you like, but over a network it won't make much difference
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Your code fails to logically match this at several points.
Also available() is not a valid way to determine either a file size or the size of an incoming network transmission - see the Javadoc. It has few if any correct uses and these aren't two of them.

Categories