Android客户端Socket读取服务器消息时readText阻塞问题求助
问题分析
你的问题出在BufferedReader.readText()方法上——它会一直阻塞直到输入流到达末尾(EOF),也就是只有当C++服务器关闭Socket连接时,这个方法才会返回。这就是为什么你看到只有关闭服务器才能读取到消息的核心原因。
解决方案
针对你的场景(后续还要传输图像缓冲区),推荐两种可靠的消息读取方式:
1. 基于换行符的文本消息分隔(适合文本通信)
如果服务器发送的是文本消息,约定每条消息末尾加上换行符\n,客户端用readLine()读取,它会在遇到换行符时立即返回,不会阻塞等待流关闭。
修改listenForServerMessage方法:
fun listenForServerMessage() { Log.d("ServerMain ", "listenForServerMessage") Thread(Runnable { try { Log.d("ServerMain ","letsgo:"+singleton_ServerInfos.end); val bufReader = BufferedReader(InputStreamReader(singleton_ServerInfos.clientSocket.getInputStream())) while (!singleton_ServerInfos.end) { Log.d("ServerMain ", "waiting for message") // 用readLine替换readText,读取到换行符就返回 val message = bufReader.readLine() if (message != null) { Log.d("ServerMain read: ", "Received: $message") // 切换到UI线程更新界面 requireActivity().runOnUiThread { // 这里添加UI更新逻辑 } } else { // 流已关闭,退出循环 break } } } catch (e: Exception) { Log.d("ServerMain: ", "exception: ${e.message}") } finally { // 确保关闭Socket资源 singleton_ServerInfos.clientSocket?.close() } }).start() }
同时需要修改C++服务器,发送消息时在末尾添加\n,示例:
// C++服务器发送文本消息示例 std::string message = "Hello from server\n"; send(clientSocket, message.c_str(), message.size(), 0);
2. 基于长度前缀的二进制通信(适合图像等二进制数据)
如果后续要传输图像缓冲区这类二进制数据,更可靠的方式是先发送消息的长度,再发送实际数据。这种方式能准确控制读取的字节数,避免阻塞。
客户端修改示例:
fun listenForServerMessage() { Log.d("ServerMain ", "listenForServerMessage") Thread(Runnable { try { val inputStream = singleton_ServerInfos.clientSocket.getInputStream() val dataInputStream = DataInputStream(inputStream) while (!singleton_ServerInfos.end) { // 先读取4字节的长度(用int存储,对应Java的int类型) val dataLength = dataInputStream.readInt() if (dataLength <= 0) break // 读取对应长度的字节数据 val buffer = ByteArray(dataLength) dataInputStream.readFully(buffer) // 处理数据:文本转字符串,图像则解析为Bitmap val textMessage = String(buffer) Log.d("ServerMain read: ", "Received data length: $dataLength, content: $textMessage") // 处理图像示例: // val bitmap = BitmapFactory.decodeByteArray(buffer, 0, dataLength) } } catch (e: Exception) { Log.d("ServerMain: ", "exception: ${e.message}") } finally { singleton_ServerInfos.clientSocket?.close() } }).start() }
C++服务器对应发送逻辑:
// 发送数据前先发送长度(4字节int类型,注意字节序统一为大端序) std::string data = "Hello from server"; int dataLength = data.size(); dataLength = htonl(dataLength); // 转换为网络字节序(大端) send(clientSocket, &dataLength, sizeof(int), 0); // 发送实际数据 send(clientSocket, data.c_str(), data.size(), 0);
额外注意点
- 不要用
available()做读取判断:available()仅返回当前可读取的字节数,不能作为消息是否完全到达的可靠依据,容易出现数据读取不完整的情况。 - 资源释放要及时:在finally块中关闭Socket和流,避免资源泄漏。
- UI操作必须在主线程:所有更新界面的逻辑必须通过
runOnUiThread执行,不能在子线程直接操作UI。
内容的提问来源于stack exchange,提问作者ImLearningDontBullyMe
相关产品推荐
相关产品推荐

