如何解决Android Emulator DataInputStream 无法完全读取流
我正在开发一个 Android 应用程序,其中数据通过 Socket 连接传输到应用程序。我注意到,一旦“有效负载”变得越来越大,EOFException 越来越有可能发生,但我无法识别出清晰的模式。请注意,到目前为止,我只能在 QEMU Android 模拟器上验证这一点,在真正的 Android 设备或 Genymotion 模拟器上似乎不存在此问题。
版本信息:
- 模拟器:30.0.5-6306047 (HAXM 7.5.2)
enter code here
- Android 版本:5.1 API 22(修订版 2)
- 主机:Windows 10 专业版
考虑以下最小示例。 SocketServer
在端口 12345
上启动。用户(套接字客户端)可以选择多个字节,这个数字被发送到“服务器”,在那里生成字节并将其写入套接字输出流。客户端尝试使用 DataInputStream#readFully(byte[])
读取响应(“payload”)。
public class MainActivity extends AppCompatActivity {
Button sendBtn;
EditText bytesTf;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
bytesTf = findViewById(R.id.byteAmount);
sendBtn = findViewById(R.id.send_it);
runSocketServer();
sendBtn.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int bytes = Integer.parseInt(bytesTf.getText().toString());
runSocketClient(bytes);
}
});
}
private void runSocketClient(final int numberOfBytes) {
Runnable client = new Runnable() {
@Override
public void run() {
// Change to "10.0.2.2" if server is not running on Android
String host = "localhost";
try (Socket socket = new Socket(host,12345)) {
DataOutputStream dataOut = new DataOutputStream(socket.getoutputStream());
DataInputStream dataIn = new DataInputStream(socket.getInputStream());
dataOut.writeInt(numberOfBytes);
dataOut.flush();
byte[] data = new byte[numberOfBytes];
// Exception occurs here:
dataIn.readFully(data);
Log.i("Test",data.length + " bytes: successfully read");
} catch(IOException ex) {
Log.i("Test",numberOfBytes + " bytes: " + ex);
ex.printstacktrace();
}
}
};
new Thread(client).start();
}
private void runSocketServer() {
Runnable server = new Runnable() {
@Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(12345);
System.out.println("Listening to port " + serverSocket.getLocalPort());
while (true) {
Socket socket = serverSocket.accept();
DataInputStream dataIn = new DataInputStream(socket.getInputStream());
DataOutputStream dataOut = new DataOutputStream(socket.getoutputStream());
int amountOfBytesToGenerate = dataIn.readInt();
byte[] randomBytes = new byte[amountOfBytesToGenerate];
new Random().nextBytes(randomBytes);
System.out.println("Sending " + amountOfBytesToGenerate + " bytes to client " + socket.toString());
dataOut.write(randomBytes);
dataOut.flush();
socket.close();
}
} catch(Exception ex) {
ex.printstacktrace();
}
}
};
new Thread(server).start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main,menu);
return true;
}
@Override
public boolean onoptionsItemSelected(MenuItem item) {
return super.onoptionsItemSelected(item);
}
}
https://github.com/GitGraf/StreamExceptionExample
为简单起见,本示例中的服务器和客户端都运行在同一个模拟 Android 设备上。通过此设置,EOFException
似乎永远不会发生,无论 numberOfBytes
设置为 10 还是 1.000.000。
在现实世界中,服务器运行在同一网络中的 Windows 服务器上。要模拟这一点,请继续从 runSocketServer()
方法中删除代码,并将其放入独立 Java 应用程序的 main-method 中。在您的开发机器上启动该应用程序,将 host
中的 runSocketClient()
变量更改为“10.0.2.2”并再次运行该应用程序。
通过这种设置,如果有效负载的大小增加,套接字连接似乎会越来越频繁地失败。
1024 bytes: java.io.EOFException
java.io.EOFException
at libcore.io.Streams.readFully(Streams.java:83)
at java.io.DataInputStream.readFully(DataInputStream.java:99)
at java.io.DataInputStream.readFully(DataInputStream.java:95)
at com.example.streamreadingtest.MainActivity$2.run(MainActivity.java:64)
at java.lang.Thread.run(Thread.java:818)
我想弄清楚这种偶尔出现且不稳定的 EOFException
的根本原因,并找到正确修复它的方法。我已经尝试过尽可能远离 readFully()
并使用 read()
代替,这似乎已经有很大帮助了。但是,我认为 Android SDK 的 DataInputStream
类也大量使用 readFully()
进行内部调用。
如果您需要更多信息,请告诉我。
编辑:我已从使用 QEMU android 模拟器切换到 Genymotion,并且 EOFException
不会出现在那里,如下面的屏幕截图所示(左边是 quemu,右边是 genymotion)。 https://github.com/GitGraf/AndroidEOF
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。