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?