2

I am sending file from server to client using java socket programming. Here is my server side code:

public void fileSendingProtocol(String filePath) {

    File myFile = new File(filePath);
    byte[] mybytearray = new byte[(int) myFile.length()];

    FileInputStream fis = null;

    try {
        fis = new FileInputStream(myFile);
    } catch (FileNotFoundException ex) {
        System.err.println(ex);
    }
    BufferedInputStream bis = new BufferedInputStream(fis);

    try {

        bis.read(mybytearray, 0, mybytearray.length);
        os.write(mybytearray, 0, mybytearray.length);
        os.flush();
        System.out.println(filePath + " Submitted");
        // File sent, exit the main method
    } catch (IOException ex) {
        // Do exception handling
        System.out.println(ex.toString());
    } finally {
        try {
            os.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

Here i have closed the os in the finally block. Because if i omit os.close() then i am not able to receive the file in the client side. Here is my client file receiving code:

 public static void fileReceivingProtocol(String filePath) {

    try {
        fos = new FileOutputStream(filePath);
    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    bos = new BufferedOutputStream(fos);
    /* read question paper from the server. */
    try {       

        bytesRead = is.read(aByte, 0, aByte.length);

        do {
            baos.write(aByte);
            bytesRead = is.read(aByte);         
        } while (bytesRead != -1);
        bos.write(baos.toByteArray());
        bos.flush();
        fos.close();            

    } catch (IOException e) {
        System.err.println("IOException:  " + e);
    }

}

I need the server first send a file . Then after receiving that file the client need to send another file to server after some minutes. But if i call the os.close() in the server side then my socket get closed and i am not able to continue any further communication between then.

Developer
  • 385
  • 1
  • 3
  • 18
  • 1
    As icza sais, you need to use `flush` but you also need to implement some kind of protocol to let the client know that the file has been completely transferred without closing the stream. – Fildor Aug 26 '14 at 10:27
  • Can you please give me the protocol? i am confused how to do like you say. – Developer Aug 26 '14 at 11:22

1 Answers1

4

You do not need to close os (the OutputStream), just call its flush() method. Streams are often buffered for performance reasons. A call to flush() will instruct the implementation to send all cached data.

Most likely the file you send is small (maybe a few KB at the most) which is less than the typical cache size. If you write less data than the cache size (or the data that can be transmitted in a TCP packet in case of a Socket's OutputStream), the implementation will likely not send it for some time. flush() will send whatever data there is cached.

If your client does not know the file size (does not know how many bytes to wait for), you have to implement some kind of "protocol" to exchange these information. A very basic would be to first send the file size (number of bytes) in 4 bytes (that is the size of a Java int), and then send the content of the file. The client will know that the first 4 bytes will be the file size, and it will wait for / read that amount of bytes.

How to convert int to bytes: Convert integer into byte array (Java) or Java integer to byte array

Modified file sender

// First write the file's length (4 bytes)
int length = (int) myFile.length();
os.write((length >>> 24) & 0xff);
os.write((length >>> 16) & 0xff);
os.write((length >>>  8) & 0xff);
os.write(length & 0xff);

// And now send the content of the file just as you did

Modified file receiver

// First read the file's length (4 bytes)
int b1 = is.read();
int b2 = is.read();
int b3 = is.read();
int b4 = is.read();
if (b1 < 0 || b2 < 0 || b3 < 0 || b4 < 0)
    throw new EOFException(); // Less than 4 bytes received, end of stream
int length = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;

// And now read the content of the file which must be exactly length bytes
Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
  • But how can the Client know that the file has been completely transmitted. OP would have to send the size in Bytes first, or something like that. – Fildor Aug 26 '14 at 10:25
  • Yes obviously some kind of "protocol" have to be implemented. – icza Aug 26 '14 at 10:27
  • can you give me the modified version of the code ? As you can see i have added the flush here . And yes the file size is 20 kb , a doc file needs to be sent. – Developer Aug 26 '14 at 11:09
  • @Developer: Just always read 4 Bytes first and convert them to a number. That number is the number of Bytes you'll be expecting the Server to send next (i.e. size of the file). Then you can stop reading the stream when you have read as many bytes as predicted instead of checking for -1 readcount. This in itself is already a very simple protocol. But it will only be good for exactly this purpose. If you want other things to happen later, you'll want to make up something more elaborate. – Fildor Aug 26 '14 at 13:02
  • Done. Added examples howto send and receive the file length. – icza Aug 26 '14 at 13:20
  • i am not able to modify my receive doc file. Can you please help me with it. Here is the question link : http://stackoverflow.com/questions/25511831/failed-to-send-the-updated-file-to-client-using-java – Developer Aug 26 '14 at 18:11