I have a simple class that handles socket connections:
public class SimpleConnection {
// Socket, input and output streams
protected Socket mSocket;
protected DataInputStream mIn;
protected DataOutputStream mOut;
public boolean createConnection(String ip, int port) {
SocketAddress socketAddress = new InetSocketAddress(ip, port);
mSocket = new Socket();
try {
mSocket.connect(socketAddress, 3000);
mIn = new DataInputStream(mSocket.getInputStream());
mOut = new DataOutputStream(mSocket.getOutputStream());
} catch (IOException e) {
return false;
}
return true;
}
public boolean sendData(byte[] data) {
try {
mOut.writeInt(data.length);
mOut.write(data);
mOut.flush();
} catch (Exception e) {
e.printStackTrace();
closeSocket();
return false;
}
return true;
}
}
This has worked until Android N. With Android N, mOut.writeInt(data.length) just sends four zeros instead of the length of data.length. This causes the server to misinterpreted the message and for the whole program to not work.
I was able to "fix" the problem by converting the integer to a byte[4]:
byte[] len = Utilities.intToByteArray(data.length);
mOut.write(len);
intToByteArray is shown here.
My question is: Why isn't writeInt not working anymore on Android N? On other Android versions this code runs just fine.
I use the latest Android Studio with Java 8, gradle 2.1.3 and Android buildtools 24.0.2.
Edit: The receiving part looks like this in Qt:
void readData(QTcpSocket* client_) {
while (client_->bytesAvailable()) {
int expected_length_;
QDataStream s(client_);
s >> expected_length_;
qLog(Debug) << expected_length_;
// Read data with expected_length_
QBuffer buffer_;
buffer_.write(client_->read(expected_length_));
}
}
expected_length_ is 0 where with the fix it is 15. Interestingly, client_->bytesAvailable() is 1 with the writeInt variant on Android N.
I did another test using nc -p 1234 -l 0.0.0.0 | xxd:
▶ nc -p 1234 -l 0.0.0.0 | xxd
00000000: 0000 000f 0815 1001 aa01 0808 8edb 0110 ................
00000010: 0118 00 ...
This is the output for both variants... so it seems writeInt() works as expected, but why does it work for Android <= 6 and not for Android 7?!??
Edit2:
After analyzing the traffic I found out that the integer is split in multiple TCP frames. I changed the server code to check if client_->bytesAvailable() >= 4 and only then to read the integer from the socket. This fixed the problem and the writeInt() variant works now too.
But why did the behaviour suddenly change?