1

I have a server-client application and using java Sockets API.

The server will send bytes to the client by calling DataOutputStream's write(bytes[] b), the DataOutputStream is wrapped around client.getOutputStream directly(no Buffer here).

This is a file download functionality And I'm going to support resume, I didn't use any HTTP here, I've implemented my own simple protocol.

I've seen these questions on SO :
1-question1.
2-C# question.
3-FileChannel question.

The first doesn't answer my question, I can't wrap DataOutputStream around ByteArrayOutputStream because the latter can't be wrapped around client.getOutputStream and I don't know how to implement my own write(int i) method(And don't want to use JNI).

the second is C# not java(and it's calling WIN API anyway, I'm a linux user by the way :) ).

The third is talking about FileChannels and HTTP, As I said I'm not using HTTP and I'm using java Socket's API.

So how to get how many bytes were actually written ?

PS (EDIT)

By resume support I mean I'll give the client the ability to stop download at specific byte and then after a while(minutes,hours,days,whatever) he/she can resume download from where it has left.

Community
  • 1
  • 1
niceman
  • 2,354
  • 21
  • 49
  • It is transparent for you. Once you call `socket.read(bytes)` it also returns how many bytes was read. Look this example: [http://stackoverflow.com/a/19863726/3710490](http://stackoverflow.com/a/19863726/3710490) – Valijon Nov 21 '15 at 10:24
  • @Valijon I know `socket.read(bytes)` returns how many bytes ware read, but `socket.write(bytes)` returns void not how many bytes were written, suppose the client decided to stop the download , then how will the server know that ? – niceman Nov 21 '15 at 16:18
  • as your connection is TCP, what you write is what your client read! – Valijon Nov 21 '15 at 18:46
  • @Valijon Wrong. The writer can be many kilobytes ahead of the reader, because of his socket send buffer and the reader's socket receive buffer. – user207421 Nov 21 '15 at 22:39

2 Answers2

2
  • The number of byes written by write(int c) is 1.

  • The number of bytes written by write(bye[] buffer) is given by buffer.length.

  • The number of bytes written by write(bye[] buffer, int offset, int length) is given by length.

Just as it says in the Javadoc.

user207421
  • 289,834
  • 37
  • 266
  • 440
  • if the client stopped the download(which I'm planning for my resume support) then `write(byte[] buffer)` won't be given by buffer.length. – niceman Nov 21 '15 at 16:17
  • 1
    @niceman Wrong. If the client stopped the download *and* its receive buffer was full *and* the sender's send buffer was full so that the sender was blocked in `write()` *and* the client closed the socket, `OutputStream.write()` would *throw an IOException.* In all other circumstances, the write would succeed completely and transfer all the data out of the buffer. In no case would it transfer less and return without throwing an exception. – user207421 Nov 21 '15 at 16:28
  • Hmmm I thought of that, so I can do my resume support in the catch clause, but then how to know if the exception was due to the client or something else(sidenote: it's strange that read doesn't throw an Exception while write does) – niceman Nov 21 '15 at 16:29
  • 1
    @niceman Wrong again. `read()` does throw an `IOException` if the connection has been reset. It seems to me that you're asking a different question. You need to know how much data the client has *read,* which is not the same as how much data the sender has written, because of TCP buffering at both ends. The only way to know that is for the client to tell you in the download protocol. Probably the real answer is for the client to tell you where to resume from when it resumes, as in HTTP. I don't know what you mean by 'I thought of that' when it didn't prevent you from uttering this mistake. – user207421 Nov 21 '15 at 16:40
  • admit: I downvoted and my question deserves downvote, but there is someone else who downvoted too, by the way I tried to disable my downvote but it's locked :) – niceman Nov 22 '15 at 17:33
  • I have corrected my unintentional mistake while getting score break up from mobile. First time I have tested this feature from mobile. Mobile does not show score break-up like in desktop client. Depending on the position of click, it will upvote and downvote. – Ravindra babu Nov 23 '15 at 05:34
1

When you write the data as byte array, write the size of the data too. When you read the data, read the size and construct byte array.

I prefer and use this approach to send large files (> 10 MB) including images from client to server. By writing the size upfront, you know how many bytes to read from byte[]

Have look at this one or this article to convert file into byte[] and back

/*  Convert File to byte[] msgBytes */


/* Write byte array */
OutputStream out = socket.getOutputStream(); 
DataOutputStream dos = new DataOutputStream(out);
int length = msgBytes.length;// it is byte array of message to be sent
dos.writeInt(length);
if (length > 0) {
    dos.write(msgBytes);
}

/*Read byte array */
DataInputStream dis = new DataInputStream(socket.getInputStream());
int length = dis.readInt();                   
if(length>0) {
    byte[] msgBytes = new byte[length];
    dis.readFully(msgBytes, 0, length); 
}

/* Now you can convert byte array back to File*/

EDIT: (for resuming download, which is not part of original post when I answered)

  1. Save the number of bytes you have read from the server at client (use inputStream.read() instead of inputStream.readFully()

  2. Skip that value (bytesAlreadyRead) when you re-connect to server

Community
  • 1
  • 1
Ravindra babu
  • 42,401
  • 8
  • 208
  • 194
  • I'm already doing this, after `dos.write(msgBytes)`, how do I know that length is what actually was written ? – niceman Nov 21 '15 at 16:15
  • If you are looking to resume file reading from the point where it was paused lost time, have a look at : http://stackoverflow.com/questions/22107380/resume-file-upload-download-after-lost-connection-socket-programming – Ravindra babu Nov 23 '15 at 05:30