0

I'm used to using Winsock in C++, and I have a server app that sends and receives data with headers similar to HTTP format.

When I use recv() in c++ with a sufficiently large buffer, I will always receive my whole packet...

Does the DataStreamInput.read() act similarly? I haven't yet been able to receive a message, and I'm thinking I'm not getting the whole message before it iterates to read again...

As I'm writing this on Windows for Android, it's tough to debug, just wondering if there's a way that would be closer to my C++ code?

user207421
  • 305,947
  • 44
  • 307
  • 483
Wyllow Wulf
  • 410
  • 4
  • 23
  • "When I use recv() in c++ with a sufficiently large buffer, I will always receive my whole packet." No you won't. It is only specified to block until at least one byte has been transferred. It is easy to devise cases where you won't receive the entire transmission. – user207421 Nov 02 '15 at 03:22

3 Answers3

1

DataInputStream.read(byte[]) will read an arbitrary number of bytes up to the passed in byte array length and return. The number of bytes read will be the return value or it will be -1 if the end of the stream has been reached. The call will block until some bytes are available, the end of stream is reached, or an IOException occurs.

You need to check the return value to see how many bytes were read, if your expecting more data, continue calling it until you have all the data you need.

If you know you need 100 bytes for instance

InputStream in = ...
byte b = new byte[100]
int c = 0;
int read = 0;
while(c < b.length && read != -1){
   read = in.read(b, c, b.length - c)
   if(read != -1)
     c += read;
   } 
}
Dev
  • 11,919
  • 3
  • 40
  • 53
  • As data is sent through the internet in packets (or frames or segments w/e), is it safe to assume that DataInputStream.read() will read at the very least one packet's worth of data (if any)? My c++ client read data very easily, and all at once... I would prefer to not have to write a huge chunk of code to put all my data back together after Java tears it apart. – Wyllow Wulf Nov 02 '15 at 01:35
  • @Willdorf It isn't, the API only guarantees that it will read what the return value says it reads for any given call. It may return 1 byte at a time and still be in spec. – Dev Nov 02 '15 at 01:37
  • 2
    @Willdorf Java doesn't 'tear it apart'. It gives you exactly and only what TCP gives it. That can be as little as one byte at a time. – user207421 Nov 02 '15 at 03:21
  • Are you looking for [`DataInputStream.readFully`](http://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html#readFully(byte[])) ? – Louis Wasserman Nov 02 '15 at 05:27
  • Well, what I'm saying is, that my server app sends out a TCP segment with no less than 71 bytes of data (plus TCP header), a 70-byte app header and at least one byte of app data. TCP on the client side should receive this all at once and then send the whole segment's worth of app data to the buffer, and it appears (correct me if i'm wrong) that DataInputStream.read() will read less than this, while Winsock's recv() is a bit more patient, and will make sure the whole segment's app data gets to the buffer in one read. – Wyllow Wulf Nov 02 '15 at 21:19
  • That being said, I put a Thread.sleep(1000) in the read loop and it now works as expected. (I'm going to experiment to see what's the minimum required for it to run seamlessly) – Wyllow Wulf Nov 02 '15 at 21:29
  • 1
    @Willdorf Have a look at the Javadoc. It isn't contracted to transfer more than one byte at a time. There is no such thing as a message in TCP. It's a byte-stream protocol. There is no basis for your expectation. Adding sleeps to network code is just cargo-cult programming. You've been given a solution. Use it. – user207421 Nov 02 '15 at 23:18
0

Can you do something like before sending the file write the length: outToServer.writeInt(sendData.length);

Then when you receive the file read the length and use it as the length?

int dataLength = dis.readInt()
  byte[] receivedData = new byte[dataLength];

I might not be understanding the question though

kyle heitman
  • 114
  • 6
0

Is there a blocking-type socket receive in Java?

Yes. All of java.net is blocking. But that isn't what you're actually asking for. What you're asking for is a read method that will fill your buffer. What you are looking for is provided by DataInputStream.readFully(), although you are mistaken in asserting that recv() always fills the buffer in C++. It doesn't, and in some circumstances it can't: when the buffer size exceeds the size of the socket receive buffer.

user207421
  • 305,947
  • 44
  • 307
  • 483