【发布时间】:2020-10-02 09:48:18
【问题描述】:
我正在将 Java 桌面项目转换为 Android。其中一部分包括到服务器的 TCP 连接以及从服务器到客户端(Android 应用程序)解析长文本。这是我也尝试在 Android 中使用的桌面项目的代码:
// Method is called when a button is tapped
public void tapButton() {
// Create a message to the server that requests for the Departure navdata
String messageToServer = someMethodToMakeHandshakeMessage();
// Connect to the server
if (!messageToServer.equals("")) {
String finalMessageToServer = messageToServer;
new Thread(() -> {
String navdata = connectClient(finalMessageToServer);
getActivity().runOnUiThread(() -> messageReceived(navdata));
// I am also using messageReceived(navdata) without runOnUiThread with the same result
}).start();
}
}
public String connectClient(String messageOut) {
Socket socket = null;
DataInputStream input = null;
DataOutputStream output = null;
BufferedReader br = null;
// Final message from the server
String data = "";
// Message from the server that should terminate TCP connection
String terminator = "END_DATA";
try {
// Create socket and streams
socket = new Socket(someIPAddress, somePort);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
//Send message to the server
output.writeBytes(messageOut);
//Read Response
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder sb = new StringBuilder();
String s = "";
int value = 0;
// Process the message from the server and add to the StringBuilder
while((value = br.read()) != -1) {
// converts int to character
char c = (char)value;
sb.append(c);
if(sb.toString().contains(terminator)) {
break;
}
}
// Create the final string
data = sb.toString();
}
catch (UnknownHostException e) {
// Dealing with exception
}
catch (EOFException e) {
// Dealing with exception
}
catch (IOException e) {
// Dealing with exception
}
finally {
try {
if(socket!=null) { socket.close();}
if(input != null) { input.close();}
if(output != null) { output.close();}
if(br != null) { br.close();}
}
catch (IOException ex) {
// Dealing with exception
}
socket = null;
input = null;
output = null;
br = null;
}
return data;
}
public void messageReceived(String message) {
// Method to deal with received data
}
虽然代码在桌面 Java 应用程序中运行良好,但我在使用 Android 时遇到了问题(使用模拟器)。文本不是全长发送的,而是在中间某处被剪切(客户端仅收到 20-50%;解析的字符数一直不同)。此外,我注意到连接服务器花费的时间太长,但我想这是由于使用了模拟器。
从服务器接收长文本的 TCP 客户端是否应该在 Android 中以不同的方式实现?
编辑:使用@blackapps 的建议实现了以下代码:
String line = br.readLine();
while (line != null) {
sb.append(line);
line = br.readLine();
if (line.trim().isEmpty()) {
Log.i("EMPTY LINE>>>>>>>>>>>>>>>>>",line);
}
if(line.equals(terminator)) {
break;
}
}
// Create the final string
data = sb.toString();
}
两个问题。我想在收到的文本中保留空行。未检测到终止符。我认为,它用两个空行与正文分开。但是,在第一个空行之后,它进入无限循环并且连接永远不会终止。
编辑#2。
在花了几个小时试图弄清楚发生了什么之后,对服务器进行了更改,并比较了发送和接收的字节数,我注意到这不是代码的问题。客户端似乎收到了全文。问题在于如何使用 Log.i(String, String) 方法将文本写入控制台。我在代码中添加了旧的System.out.println(),整个文本显示在控制台中。但是,来自 Log.i() 的文本在中间被截断。这是我第一次使用 Android Studio,到底发生了什么?
非常感谢!
【问题讨论】:
-
input = new DataInputStream(socket.getInputStream())。如果您没有使用input,那为什么会出现呢? -
您正在逐字节读取。非常低效。特别是当您还将每个字符的 sb 转换为字符串时。尝试使用 br.readLine()。
-
让服务器在单独的行上发送“END_DATA\n”。然后检查该字符串的行。不是全部。
-
sb.append(line);那应该是sb.append(line).append("\n");以保留行和空行。将此语句放在 readLine() 语句之后。 -
The terminator is separated from the text by two empty lines.好的。那不重要。请确保服务器在终止符之后发送一个 \n。