Java Android N-DataOutputStream.writeInt()行为已更改?
我有一个处理套接字连接的简单类:Java Android N-DataOutputStream.writeInt()行为已更改?,java,android,sockets,Java,Android,Sockets,我有一个处理套接字连接的简单类: public class SimpleConnection { // Socket, input and output streams protected Socket mSocket; protected DataInputStream mIn; protected DataOutputStream mOut; public boolean createConnection(String ip, int port
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;
}
}
这一直有效到安卓N。使用安卓N,mOut.writeInt(data.length)
只发送四个零,而不是data.length
的长度。这会导致服务器误解消息,导致整个程序无法工作
通过将整数转换为字节[4],我能够“修复”这个问题:
byte[] len = Utilities.intToByteArray(data.length);
mOut.write(len);
将显示intToByteArray
我的问题是:writeInt
为什么不再在安卓N上工作了?在其他Android版本上,此代码运行良好
我使用的是最新的Android Studio,包括Java 8、gradle 2.1.3和Android buildtools 24.0.2
编辑:
接收部件在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_));
}
}
这是两种变体的输出。。。因此,似乎writeInt()
可以像预期的那样工作,但为什么它可以用于Android bytesAvailable()>=4,然后才从套接字读取整数呢。这解决了这个问题,writeInt()
变体现在也可以工作了
但为什么行为会突然改变
分析流量后,我发现writeInt()
刷新数据
它完全按照你说的做了DataOutputStream
未被缓冲,并且它下面没有BufferedOutputStream
,因此writeInt()
向网络写入了四个字节
过早地
TCP中不存在“过早”这样的事情。TCP不保证打包或分段。如果要控制这种所谓的“过早刷新”,请使用mOut=newdataoutputstream(newbufferedoutputstream(Socket.getOutputStream())
并在写入数据后自行刷新
所以有些帧只有一个或两个字节,这就是为什么bytesAvailable只有1个字节
- 这是你的主要问题。您误用了
。它不是消息结束指示器。请参阅Javadocavailable()
- 您也没有检查是否确实读取了长度单词的四个字节
- 据我所知,您也没有检查是否已收到所有字节的数据
if(客户机->字节可用()<4)后中断代码>并等待更多数据,它可以工作。但我仍然不明白为什么行为会改变
它可以随时改变。你的代码中断了,因为它依赖于几个无效的假设。你可以保证数组的长度实际上不是0
?声称内部方法被破坏是一项相当严重的指控。是的,data.length
是15
,而不是0
。这令人难以置信。如果这个方法被破坏,那么JDK的一半将无法工作。显示您的接收代码。我确切地知道Qt的zip,但肯定s>>预期长度是否进行ASCII转换?您还没有显示实际读取了那么多字节的部分,这是大多数此类代码的地方。在Java中,您需要使用DataInputStream.readFully()
,或相应的循环:否则您将与发送方不同步。我编辑了服务器端代码<代码>预期长度为0,因此缓冲区没有数据。问题是,服务器代码和客户机代码可以运行数月甚至数年。只有安卓N,它突然停止工作。安卓N在发送整数的四个字节之前是否刷新了数据?谢谢你的回答,我现在明白我做错了什么。我更改了mOut
,按照您的建议添加了BufferedOutputStream
,并正确检查了服务器代码中的长度。哇,感谢您的回答!就连我也面临着同样的问题(该应用程序是针对棉花糖n,而不是牛轧糖)。这真是太好了!
▶ nc -p 1234 -l 0.0.0.0 | xxd
00000000: 0000 000f 0815 1001 aa01 0808 8edb 0110 ................
00000010: 0118 00 ...