I have a case where the server sends the file size first and the file data. How do I differentiate both the integer value and the file data when being read at the client side?
Sameple code for server (os is the bufferedoutputstream):
// Construct a 1K buffer to hold bytes on their way to the socket.
byte[] mybytearray = new byte[(int) myFile.length()];
//File Size
os.write((int) myFile.length());
FileInputStream fis = null;
System.out.println("test+sendbytes");
// Copy requested file into the socket's output stream.
try {
fis = new FileInputStream(myFile);
} catch (FileNotFoundException ex) {
// Do exception handling
}
BufferedInputStream bis = new BufferedInputStream(fis);
try {
bis.read(mybytearray, 0, mybytearray.length);
os.write(mybytearray, 0, mybytearray.length);
os.flush();
os.close();
os.close();
// File sent, exit the main method
return;
} catch (IOException ex) {
// Do exception handling
}
You need to write the length as an int unless you are assuming all files arfe no more than 255 bytes long. Try DataOutputStream.writeInt()
For the read you have to assume an order. ie you assume the length is sent first followed by the contents. Use DataInputStream.readInt() to read the length.
Related
I am writing a file storage and transfer system using Java. Here's the code on the client side to receive a file:
public static void receiveFile(Socket socket) throws IOException{
String fileLocation="/home/limafoxtrottango/Downloads/receivedFile";
int bytesRead=0;
int current = 0;
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
// receive file
byte [] byteArray = new byte [60022386];
System.out.println("Waiting to receive a file...");
//reading file from socket
InputStream inputStream = socket.getInputStream();
fileOutputStream = new FileOutputStream(fileLocation);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
bytesRead = inputStream.read(byteArray,0,byteArray.length); //copying file from socket to byteArray
current = bytesRead;
do {
bytesRead =inputStream.read(byteArray, current, (byteArray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
bufferedOutputStream.write(byteArray, 0 , current); //writing byteArray to file
bufferedOutputStream.flush(); //flushing buffers
System.out.println("File " + fileLocation + " downloaded ( size: " + current + " bytes read)");
} catch(SocketException e){
System.out.println("Some error occured");
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
if (fileOutputStream != null) fileOutputStream.close();
if (bufferedOutputStream != null) bufferedOutputStream.close();
if (socket != null) socket.close();
}
}
While receiving a file, I get the following error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:128)
at Test.receiveFile(Test.java:211)
at Test.main(Test.java:70)
Note: The error is in the following line of the code:
bufferedOutputStream.write(byteArray, 0 , current);
After debugging, I found-out that the client does not have any data in it's input stream, and hence, the read() method always returns -1 (eof). But the server is sending the file successfully.
Here is the code for the server:
public static void sendFile(Socket socket, String fileLocation)
{
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
OutputStream outputStream = null;
File file = new File (fileLocation);
byte [] byteArray = new byte [(int)file.length()];
try {
socket=new Socket(socket.getInetAddress(),port_no);
fileInputStream = new FileInputStream(file);
bufferedInputStream = new BufferedInputStream(fileInputStream);
bufferedInputStream.read(byteArray,0,byteArray.length); // copied file into byteArray
//sending file through socket
outputStream = socket.getOutputStream();
System.out.println("Sending " + fileLocation + "( size: " + byteArray.length + " bytes)");
outputStream.write(byteArray,0,byteArray.length); //copying byteArray to socket
outputStream.flush(); //flushing socket
System.out.println("Done sending!");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And here is my call to the above method:
sendFile(clientSocket, "/home/limafoxtrottango/Downloads/serverDownloads/"+sender);
The thing is that the server is successfully writing the byte into the stream, but the client doesn't seem to have any data in it's input stream.
https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#read(byte[],%20int,%20int)
inputStream.read(byteArray,0,byteArray.length); may return -1 in some cases as given in documentation above. Please cater for such situations.
In addition, I would suggest to use solution given here for both client and server: Efficient way to write InputStream to a File in Java (Version 6)
Client code:
final Path destination = Paths.get(fileLocation);
try (
final InputStream in = socket.getInputStream();
) {
Files.copy(in, destination);
}
Server code:
try (
final InputStream in = new FileInputStream(fileLocation);
) {
Files.copy(in, socket.getOutputStream());
}
Kind regards,
Bala
The server isn't sending anything, contrary to your title. It is closing the connection immediately, so bytesRead is initially -1 and never changes, and you aren't defending against that, so you get the ArrayIndexOutOfBoundsException.
However in the code you posted, the server is sending something but never closing the socket, which is another bug you need to fix. It is also ignoring the count returned by FileInputStream.read() and assuming it filled the buffer, which isn't part of the specification.
So either this is not the real server code or you are connecting to something else, or the server got an IOException that you haven't mentioned.
It's curious that you use two different pieces of code for copying. The standard way to copy a stream in Java is this:
char buffer = new char[8192]; // or whatever size you prefer > 0
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Use this at both ends. There is no need for heroically sized buffers, or buffers the size of the file, or assuming that the file size fits into an int.
I am implementing two programs; Client and Server, and client asks for a file from server to download in local file system.
After downloading one file, the client should be able to download another file if it wishes to..
However after it downloads the file, Server gives me an exception says
java.net.SocketException: Socket closed
Here's my code..
Client:
byte[] aByte = new byte[0];
int bytesRead;
String msg;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
while (!(msg = input.readLine()).equals("end")) {
String myFolderName = "ServerFolder";
File folder=new File(myFolderName);
if (!folder.exists()){
folder.mkdir();
}
System.out.println("file downloading");
try {
System.out.println("1");
fos = new FileOutputStream("ServerFolder/"+fileToDownload);
bos = new BufferedOutputStream(fos);
System.out.println("MSG: "+msg);
bytesRead = in.read(aByte, 0, aByte.length);
System.out.println("2");
do {
baos.write(aByte);
bytesRead = in.read(aByte);
} while (bytesRead != -1);
System.out.println("3");
bos.write(baos.toByteArray());
bos.flush();
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
bos.close();
} catch (IOException ex) {
System.err.println(ex);
}
Server:
if (outToClient != null) {
System.out.println("2");
File myFile = new File(msg);
byte[] mybytearray = new byte[(int) myFile.length()];
try {
fis = new FileInputStream(myFile);
} catch (FileNotFoundException ex) {
// Do exception handling
}
System.out.println("3");
bis = new BufferedInputStream(fis);
try {
bis.read(mybytearray, 0, mybytearray.length);
System.out.println("mybytearray.length: "+(int) myFile.length());
out.write((int) myFile.length()+"\r\n");
out.write("end\r\n");
out.flush();
outToClient.write(mybytearray, 0, mybytearray.length);
outToClient.flush();
s.shutdownOutput();
outToClient.close();
System.out.println("4");
} catch (IOException ex) {
System.out.println("5");
System.err.println(ex);
}
(All connection stuff are done in the beginning of each method)
I had
s.close();
in the Server but I deleted it just in case it causes the error but its not..
I am presuming that
outToClient.close();
is not causing it either?...
Also I googled this problem and some people suggested to tell the client the size of the file before the server sends the file.. but it didn't work as well.. so I deleted that part as well(or maybe I did it wrong..)
Thanks:)
java.net.SocketException: Socket closed
This has one meaning only. You closed the socket, then you continued you use it. Possibly you are unware that closing either the input or the output stream of a Socket closes the other stream and the socket.
There are numerous other errors in your code: you are ignoring the value returned by read(); you are using unnecessary BytearrayOutputStreams when you could be writing directly to the target; etc etc. Too numerous to mention really. The canonical way to copy a stream in Java is as follows:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
If you want to use the same connection to transfer more than one file you will have to send the length of the file ahead of the file so the peer knows when it has read all the file, using an obvious modification of the above loop. DataOutputStream.writeLong() and DataInputStream.readLong() provide the most obvious ways of doing that.
I have some client server socket code and am transferring binary files between a Windows 7 machine and a SUSE Linux box. When I transfer a file from Win7 to Linux, they end up with the same MD5 Checksum so I know they are identical. But when I transfer from Linux to Win7, the checksums don't agree, indicating that the file did not transfer properly.
Anybody run into this? I'm using ObjectOutputStreams and DataInputStreams and the code is the same on both sides.
// connect socket to server socket, etc
//........
//=======================
// read the file
try {
size = file.length();
byteArr = new byte[(int) size];
dis = new DataInputStream(new FileInputStream(file));
dis.read(byteArr, 0, byteArr.length);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
//=======================
// then send it
try {
oos.writeObject(byteArr);
oos.flush();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
// then close oos, dis, etc
InputStream.read is not guaranteed to fill the input array. It guarantees at least 1 byte is read and no more than can fit in the array, or 0 bytes if the end of file is reached, or an IOException. It may be that under linux you are not getting the whole file in one go.
Also, why are you filling a byte array and then sending it as an object? Streams are conceptualised as streams of bytes, there is no need for an array.
eg.
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
FileInputStream input = new FileInputStream(file);
int read;
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
// flush and close everything
I am working on transferring a file between two computers over a socket. Everything seems to work, but when I look at the contents of the retrieved file, it is empty. What am I doing wrong?
Here is my server-side code. The file foobar.txt exists, and its contents are "hello world!".
try{
ServerSocket ssock = new ServerSocket(12345);
Socket sock = ssock.accept();
//here I get the filename from the client, but that works fine.
File myFile = new File("foobar.txt");
byte[] mybytearray = new byte[(int) myFile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
bis.read(mybytearray, 0, mybytearray.length);
OutputStream os = sock.getOutputStream();
os.write(mybytearray, 0, mybytearray.length);
os.flush();
sock.close();
} catch (Exception e){
e.printStackTrace();
}
And here is my client code:
try {
Socket socket = new Socket(host, port);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.print("get foobar.txt\r\n");
out.flush();
byte[] streamIn = new byte[1024];
InputStream in = socket.getInputStream();
FileOutputStream file_src = new FileOutputStream("foobar.txt");
BufferedOutputStream file_writer = new BufferedOutputStream(file_src);
int i;
while ((i = in.read()) != -1) {
file_writer.write(i);
}
file_writer.flush();
file_writer.close();
file_src.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
Solved
Since I am using multiple threads and multiple sockets and testing all connections on one machine, I was simply running into a problem where the client (which has both the client and server code in it) would connect with itself instead of the other client. Changing the file transfer port for the different running clients got this all to work. Thanks for everyone who had a look at this and gave me some suggestions.
Maybe you're closing the wrong socket on the client. When you close the socket, you're closing the class field this.socket instead of the local variable socket.
Also, when you close the output stream to the file, you don't have to close both the BufferedOutputStream and the FileOutputStream. The FileOutputStream is automatically closed when the BufferedOutputStream is closed.
One more thing---you don't have to flush an output stream before closing it. When you call close() the stream is automatically flushed.
In addition to what everyone else has said, you are ignoring the result of bis.read(). It isn't guaranteed to fill the buffer. See the Javadoc.
The correct way to copy streams in Java, which you should use at both ends, is this:
byte[] buffer = new byte[8192]; // or whatever
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
The only thing I think of that is that you actually never start receiving the file because the server-side doesn't read the command ("get foobar.txt"), so the client-side freezes on sending the command.
The existence of the file at the client-side might be from previous tests.
But, I'm not sure this is the problem. It's just a try to help.
I have written a java code which sends a .exe file from the server to the client using FileInputStream and BufferedInputStream, but the file gets corrupted at the client side.
What could be the reason?
command1= ServerFrame.msg1+".exe";
File p=new File(command1);
FileInputStream f=new FileInputStream(p);
BufferedInputStream bis=new BufferedInputStream(f);
Integer d=bis.available();
int d1=d;
byte b[]=new byte[d];
bis.read(b,0,d1);
System.out.println(d1);
dos=new DataOutputStream(s.getOutputStream());
BufferedOutputStream bos=new BufferedOutputStream(s.getOutputStream());
dos.writeUTF(d.toString()); // sending length in long
bos.write(b,0,d1); // sending the bytess
bos.flush();
bis.close();
bos.close();
dos.close();
I suppose that s is your socket. There are few thing that can be wong in your code:
bis.available() returns the number of bytes that can be read without bocking, not the total size of the file, you should use a loop to read the file
you use the output stream in two different buffers and you write to both of them without flushing; also, why are you writing UTF?
Here is what you intend to do:
private void copy(InputStream in, OutputStream out) {
byte[] buf = new byte[0x1000];
int r;
while ((r = in.read(buf)) >= 0) {
out.write(b, 0, r);
}
}
InputStream in = new BufferedInputStream(new FileInputStream(path));
OutputStream out = new BufferedOutputStream(s.getOutputStream());
copy(in, out);
in.close();
out.close();
bis.available() returns the bytes available for read, it may not be the full content size, u have to read in a loop till it reaches EOF.
in case someone stuck with same problem, buffer size is the culprit in this case :
Integer d=bis.available();
byte b[]=new byte[d];
It should be lesser try 1024 or something:
byte b[]=new byte[1024];
hope this helps..