i have a FileServer and a FileClient, server sends a file, when client connects. it is a simple program, just to understand the concept behind.
I am able to send the file from Server to Client, with a buffer of 1024.
The problem is that the recieved file is always around 0.01 MB less than the original file.Thus mp3 files lose some info, and video files just doesn't play.
I put some prinln statements in my while loops in both Server & Client. i found that my server is not sending the whole file.
//Server
byte [] mybytearray = new byte [1024];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
OutputStream os = sock.getOutputStream();
System.out.println("Sending...\n mybytearray length:"+mybytearray.length+"file length:"+(int)myFile.length());
int read, readTotal=0;
while ((read = fis.read(mybytearray,0,mybytearray.length)) != -1) {
os.write(mybytearray, 0, read);
System.out.println("File REad:"+read+"readtotal:"+readTotal); //*
readTotal += read;
}
System.out.println("Final File Read:"+read+" Final readtotal:"+readTotal);
os.flush();
sock.close();
}
The Println statement output is:
Sending...
mybytearray length:1024file length:12767554
File REad:1024readtotal:0
File REad:1024readtotal:1024
.............and a lot of it...and then
File REad:1024readtotal:12756992
File REad:1024readtotal:12758016
File REad:322readtotal:12759040
Final File Read:-1 Final readtotal:12759362
The file length:12767554 & Last readTotal: 12759362 shud be equal. i don't understand why the last read value is lower [322], while it can still have 1024.
Any kind of help wud be appreciated.
Thanks.
[EDIT]
//Client
int read;
int totalRead = 0;
while ((read = is.read(mybytearray,0,mybytearray.length)) != -1) {
bos.write(mybytearray, 0 , read);
totalRead += read;
System.out.println("\nread:"+read+"\ntotalread: "+totalRead);
}
System.out.println("Final File Read:"+read+" Final readtotal:"+totalRead);
bos.write(mybytearray, 0 , read); //57 Line in FileClient.java
bos.flush();
i again tried to send a file. a txt this time.
this is my server's output
Sending...
mybytearray length:1024file length:1232
File REad:1024readtotal:0
File REad:208readtotal:1024
Final File Read:-1 Final readtotal:1232
and this one on client
read:208
totalread: 1232
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
Final File Read:-1 Final readtotal:1232
at java.lang.System.arraycopy(Native Method)
at java.io.BufferedOutputStream.write(Unknown Source)
at FileClient.main(FileClient.java:57)
readtotal values are same, but sometimes i get this error, sometimes i don't.
[BIG EDIT--COMPLETE CLIENT CODE]
public class FileClient{
public static void main (String [] args ) throws IOException {
long start = System.currentTimeMillis();
int bytesRead;
int current = 0;
final JFrame f = new JFrame("Sample");
f.getContentPane().setLayout(new FlowLayout());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(590,490);
f.setVisible(true);
// localhost for testing
Socket sock = new Socket("localhost",13267);
System.out.println("Connecting...");
File f1=new File(RecieveObject(sock));
// receive file
byte [] mybytearray = new byte [1024];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream(f1);
ProgressMonitorInputStream nn= new ProgressMonitorInputStream(f,"reading",is);
BufferedOutputStream bos = new BufferedOutputStream(fos);
/* bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead =
is.read(mybytearray, current, (mybytearray.length-current));
System.out.println("mybytesarray length: "+mybytearray.length+"\ncurrent:"+current+"\nbytesread: "+bytesRead);
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
bos.write(mybytearray, 0 , current);
bos.flush();
*/
int read;
int totalRead = 0;
//InputStream clientInputStream = clientSocket.getInputStream();
while ((read = is.read(mybytearray,0,mybytearray.length)) != -1) {
bos.write(mybytearray, 0 , read);
totalRead += read;
System.out.println("\nread:"+read+"\ntotalread: "+totalRead);
}
System.out.println("Final File Read:"+read+" Final readtotal:"+totalRead);
// bos.write(mybytearray, 0 , read);
bos.flush();
long end = System.currentTimeMillis();
System.out.println(end-start);
bos.close();
sock.close();
}
public static String RecieveObject(Socket s) {
String str = null;
try{
ObjectInputStream is = new ObjectInputStream(s.getInputStream());
str =(String)is.readUTF();
}
catch(IOException ex){}
return str;
}
}
You're missing the beginning of the file (up to the first 1024 bytes), due to your 5th line (including the comment). You read from the input and advanced it, without sending it to the client. Remove this:
bis.read(mybytearray,0,mybytearray.length);
Additionally, you're not using the BufferedInputStream in your loop. Either use bis.read here instead of fis.read (if you still want buffered reads) - or remove the BufferedInputStream all together.
Your other problem is that you're reading the final bytes on the client, then entering the loop once more. is.read is again called. Instead of returning -1, it's throwing an IOException as the other side of the socket has been closed. As such, bos.flush() and bos.close() aren't getting called, and your final bytes are never written to disk. To assist with this, try calling sock.shutdownOutput before closing it. Regardless, you'll want to add some proper exception handling around this.
byte [] mybytearray = new byte [1024];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream os = sock.getOutputStream();
System.out.println("Sending...\n mybytearray length:"+mybytearray.length+"filelength:"+(int)myFile.length());
int read, readTotal=0;
while ((read = bis.read(mybytearray,0,mybytearray.length)) != -1) {
os.write(mybytearray, 0, read);
System.out.println("File REad:"+read+"readtotal:"+readTotal); //*
readTotal += read;
}
System.out.println("Final File Read:"+read+" Final readtotal:"+readTotal);
os.flush();
sock.close();
}
Related
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();
}
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)).
i've created an application which send image from server (desktop) to client (android) via socket programming............the problem is i'm getting the file at the client side (android), but with no content.
can anyone please tell me what's the problem
Client side (Android)
DataInputStream dis=new DataInputStream(socket.getInputStream());
receiveFile(dis); // call method receiveFile()
public Bitmap receiveFile(InputStream is) throws Exception{
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "myFile.png";
String imageInSD = baseDir + File.separator + fileName;
System.out.println("FILE----------------->"+imageInSD);
int filesize=6022386;
int bytesRead;
int current = 0;
byte [] data = new byte [filesize];
FileOutputStream fos = new FileOutputStream(imageInSD);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(data,0,data.length);
current = bytesRead;
int index = 0;
while (index < filesize)
{
bytesRead = is.read(data, index, filesize - index);
if (bytesRead < 0)
{
throw new IOException("Insufficient data in stream");
}
index += filesize;
}
bos.write(data, 0 , current);
bos.flush();
bos.close();
return null;
}
Server (Desktop)
send(socket.getOutputStream()); // call method send()
public void send(OutputStream os) throws Exception{
// sendfile
File myFile = new File ("C:/div.png");
System.out.println("the file is read");
byte [] mybytearray = new byte [(int)myFile.length()+1];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
System.out.println("Sending...");
os.write(mybytearray,0,mybytearray.length);
os.flush();
}
The correct way to copy a stream in Java is as follows:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
At present your code:
Assumes read() fills the buffer. There is nothing in the Javadoc that says so.
Ignores the result returned by read(), which in addition to being the invaluable count, could also be -1 indicating EOS.
Wastefully allocates a buffer the entire size of the file.
Assumes the size of the file fits into an int.
Relies on the receiver magically knowing the size of the incoming file.
The code above makes none of these assumptions, and works with any buffer size from 1 upwards.
Looking at your code, I see you want to receive a file save it to the external storage and return the Bitmap of that file. That's what I guess you want to do but your code, as it is, does not do that. If you want you can use the following code to accomplish that task. First the server sends 4 bytes indicating the file's size followed by the file's contents; the client read that 4 bytes and then reads the whole file saving it to disk every chunk it reads. Finally, it converts the received file to a bitmap and returns it.
The client code:
public Bitmap receiveFile(InputStream is) throws Exception
{
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "myFile.png";
String imageInSD = baseDir + File.separator + fileName;
System.out.println("FILE----------------->" + imageInSD);
// read first 4 bytes containing the file size
byte[] bSize = new byte[4];
is.read(bSize, 0, 4);
int filesize;
filesize = (int) (bSize[0] & 0xff) << 24 |
(int) (bSize[1] & 0xff) << 16 |
(int) (bSize[2] & 0xff) << 8 |
(int) (bSize[3] & 0xff);
int bytesRead;
// You may but don't have to read the whole file in memory
// 8k buffer is good enough
byte[] data = new byte[8 * 1024];
int bToRead;
FileOutputStream fos = new FileOutputStream(imageInSD);
BufferedOutputStream bos = new BufferedOutputStream(fos);
while (filesize > 0)
{
// EDIT: just in case there is more data in the stream.
if (filesize > data.length) bToRead=data.length;
else bToRead=filesize;
bytesRead = is.read(data, 0, bToRead);
if (bytesRead > 0)
{
bos.write(data, 0, bytesRead);
filesize -= bytesRead;
}
}
bos.close();
// I guess you want to return the received image as a Bitmap
Bitmap bmp = null;
FileInputStream fis = new FileInputStream(imageInSD);
try
{
bmp = BitmapFactory.decodeStream(fis);
}
catch (Exception e)
{
// in case of an error set it to null
bmp = null;
}
finally
{
fis.close();
}
return bmp;
}
The server code:
public void send(OutputStream os) throws Exception
{
// sendfile
File myFile = new File("C:/div.png");
System.out.println("the file is read");
int fSize = (int) myFile.length();
byte[] bSize = new byte[4];
bSize[0] = (byte) ((fSize & 0xff000000) >> 24);
bSize[1] = (byte) ((fSize & 0x00ff0000) >> 16);
bSize[2] = (byte) ((fSize & 0x0000ff00) >> 8);
bSize[3] = (byte) (fSize & 0x000000ff);
// send 4 bytes containing the filesize
os.write(bSize, 0, 4);
byte[] mybytearray = new byte[(int) fSize];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
int bRead = bis.read(mybytearray, 0, mybytearray.length);
System.out.println("Sending...");
os.write(mybytearray, 0, bRead);
os.flush();
bis.close();
}
My server is sending several files to my client. However at the client side, it only receives the first file because I don't know how to iterate and get the second file.
The Server sends like this:
ListIterator iter = missingfiles.listIterator();
//missingfiles contain all the filenames to be sent
String filename;
while (iter.hasNext()) {
// System.out.println(iter.next());
filename=(String) iter.next();
File myFile = new File("src/ee4210/files/"+filename);
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
//bis.read(mybytearray, 0, mybytearray.length);
DataInputStream dis = new DataInputStream(bis);
dis.readFully(mybytearray, 0, mybytearray.length);
OutputStream os = _socket.getOutputStream();
//Sending file name and file size to the server
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(myFile.getName());
dos.writeLong(mybytearray.length);
dos.write(mybytearray, 0, mybytearray.length);
dos.flush();
}
The client receives like this: (It will only receive the first file and I don't know how to make it loop to receive the next file)
int bytesRead;
int current = 0;
int filecount = 0;
InputStream in;
try {
in = _socket.getInputStream();
DataInputStream clientData = new DataInputStream(in);
String fileName = clientData.readUTF();
OutputStream output = new FileOutputStream(
"src/ee4210/files/"+ fileName);
long size = clientData.readLong();
byte[] buffer = new byte[1024];
while (size > 0
&& (bytesRead = clientData.read(buffer, 0,
(int) Math.min(buffer.length, size))) != -1) {
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
How to receive multiple files from outputstream?
The obvious answer is 'one at a time, with extra information to tell you where one stops and another starts'. The most usual technique is to send the file size ahead of the file, e.g. as a long via DataOutputStream.writeLong(), and at the receiver change your read loop to stop after exactly that many bytes, close the output file, and continue the outer loop that reads the next long or end-of-stream.
You can try this.
I've used a lazy method to check that the end of all 3 files have been received.
int bytesRead;
int current = 0;
int filecount = 0;
InputStream in;
try
{
in = _socket.getInputStream();
DataInputStream clientData = new DataInputStream(in);
while(true)
{
String fileName = clientData.readUTF();
// will throw an EOFException when the end of file is reached. Exit loop then.
OutputStream output = new FileOutputStream("src/ee4210/files/"+ fileName);
long size = clientData.readLong();
byte[] buffer = new byte[1024];
while (size > 0
&& (bytesRead = clientData.read(buffer, 0,
(int) Math.min(buffer.length, size))) != -1)
{
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
output.close();
}
}
catch (EOFException e)
{
// means we have read all the files
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
i am trying to transfer file through socket in java..actually i have been able to transfer..but there is one problem occured..the problem is the file sent is shrink in size..for example i transfer 300mb file, the client will receive only 299mb....i was wondering what might be the problem..
Server Side
File myFile = new File (basePath+"\\"+input.readUTF());
byte [] mybytearray = new byte [1024];
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
txtArea.append("Sending... \n");
while (true)
{
int i = bis.read(mybytearray, 0, mybytearray.length);
if (i == -1) {
break;
}
output.write(mybytearray, 0, i);
txtArea.append("Sending chunk " + i + "\n");
}
output.flush();
Client Side
output.writeUTF("get");
txtArea.append("Starting to recive file... \n");
long start = System.currentTimeMillis();
byte [] mybytearray = new byte [1024];
txtArea.append("Connecting... \n");
output.writeUTF(remoteSelection);
FileOutputStream fos = new FileOutputStream(basePath+"\\"+remoteSelection);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = input.read(mybytearray, 0, mybytearray.length);
while(bytesRead != -1)
{
bos.write(mybytearray, 0, bytesRead);
txtArea.append("got chunk" + bytesRead +"\n");
bytesRead = input.read(mybytearray, 0, mybytearray.length);
}
bos.flush();
The canonical way to copy a stream in Java is as follows:
int count;
byte[] buffer = new byte[8192]; // or whatever you like really, not too small
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Works for any length input; does not load the entire input into memory; does not add latency by so doing.
If you are sending more than one file you need to send the length first, via DataOutputStream.writeLong(); read it at the other end via the inverse function; and adjust the loop condition at the reading end to terminate after reading exactly that many bytes. Not quite as simple as it may appear; left as an exercise for the reader.