2

I am having a bit of trouble writing an android app that can communicate with my server to send and receive data. So the jist of it is that my server is written in Qt C++ and, of course, my app is written in java for android. A lot of complications have arisen from getting the socket data to be in the proper format for both sides to fully understand.

Well the problem I am having is that my client (java android) can connect to the server, send a small bit of data, and receive a response from the server. The server sends a decently large sized message of data converted to UTF-8 bytes.

QByteArray sendblock;
QDataStream out(&sendblock, QIODevice::WriteOnly);
out << (quint16)0;
char * data = msg.toUtf8().data();
out.writeRawData(data, msg.toUtf8().length());
out.device()->seek(0);
out << (quint16)(sendblock.size() - sizeof(quint16));
socket.write(sendblock);
socket.waitForBytesWritten();

The msg is a QString passed to the function.

On the client side, when the message is received, I have:

Log.d("connection", "Waiting for response");
short inSize;
inSize = in.readShort();
Log.d("connection", Integer.toString(inSize)); // the first 2 bytes are the size of the message
byte[] inData = new byte[inSize];//allocate space for the entire message
in.read(inData, 0, inSize); //read the entire message
String resp = new String(inData, 0, inSize, "UTF-8");//cast into a String
Log.d("connection", resp);

So the problem is that on differing instances of my program, the bytes cast to String differ in results.

The results of the Log.d printing the response is roughly 1445 letters (2890 bytes) of the string correctly formatted into a string, then the rest of the String ends up as "??" characters.

Rarely I get the entire message as expected with no "?" characters. Sometimes I get longer lengths of the message correctly cast as a String. Most of the time I just get 1445 of the letters correctly cast and the rest are "??" characters.

I have another client for windows computers (also written in Qt C++) that always gets the message complete and does not have this issue, so I am curious if there's something with android Strings and encoding that might be causing this problem. At first I thought it might have to do with memory allocation for the Strings, but I am pretty sure I have handled that properly with setting the sizes.

  • Try CharsetDecoder to get control over decode problems http://docs.oracle.com/javase/7/docs/api/java/nio/charset/CharsetDecoder.html – auselen Nov 09 '12 at 21:31
  • Are you actually reading the number of bytes that you are expecting? Are you using TCP/IP? – RA. Nov 09 '12 at 21:34
  • I read the number of bytes I am expecting from the first 2 bytes of the message. Yes I am using TCP/IP. – user1813365 Nov 09 '12 at 21:40
  • @user1813365 Yes, but what does `in.read` return? If you are using TCP/IP, your message always has a chance of being fragmented. – RA. Nov 09 '12 at 21:46
  • You are correct. It is also what Guido Simone has said below. I was under the assumption calling "read" handled that and read until end of stream or until the specified bytes had been read. Thanks! – user1813365 Nov 09 '12 at 22:11

1 Answers1

0

As far as I can tell, the UTF-8 encoding and endian-ness of the byte count look correct. I think the only thing you are missing is you need to do your read in a while loop, since read is not guaranteed to fill the array. Try something like this. Check the return value of read to determine how many bytes are actually read and keep reading until you have 'inSize' bytes.

Log.d("connection", Integer.toString(inSize)); // the first 2 bytes are the size of the message
byte[] inData = new byte[inSize];//allocate space for the entire message

int count = 0;
while (count < inSize)
{
   int len = in.read(inData, count, inSize - count);
   count += len;
}
String resp = new String(inData, 0, inSize, "UTF-8");//cast into a String
Log.d("connection", resp);

You would need to extend this code and handle the case where len is -1 indicating the stream is closed.

Guido Simone
  • 7,912
  • 2
  • 19
  • 21
  • Well this is indeed exactly what I needed to do. I had assumed that calling read would read until the specified bytes have been read or until the end of stream had been hit. That does not seem to be the case. I assume it's something to do with the way the packets are actually sent. – user1813365 Nov 09 '12 at 22:10