Kotlin Socket客户端可发送数据但无法接收Python服务端返回数据
Kotlin客户端无法接收Python服务端Socket返回的字符串问题解决
问题核心
Socket连接正常,Kotlin客户端能向Python服务端发送数据,但接收时流阻塞/超时,仅当使用BufferedReader.ready()时可正常运行。
代码片段
Python服务端
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.bind(server_address) server_socket.listen(1) print ('Waiting for a client connection...') connection, client_address = server_socket.accept() print ('Connected to:', client_address) # listen for data for forever while True: data = connection.recv(data_size) print ('Received', data.decode('utf-8')) # print as raw bytes sizeOfMainMsg = int(data.decode('utf-8')) data = connection.recv(sizeOfMainMsg) print ('Received', data.decode('utf-8')) # print as raw bytes toSendTry = "Sendet " connection.send(bytes(toSendTry,'UTF-8'))
Kotlin客户端(基于AsyncTask)
clientSocket = Socket(SERVER_ADDRESS, SERVER_PORT) clientSocketOut = clientSocket!!.getOutputStream() clientSocketIn = clientSocket!!.getInputStream() if (clientSocket != null) { while (clientSocketOut != null && clientSocketIn != null && clientSocket!!.isConnected()) { var tmp = clientSocketIn!!.bufferedReader(Charsets.UTF_8) if(tmp.ready()){ recived.add(tmp.readLine()) // 阻塞发生处 } if (toSend.size > 0){ for (nowMsg in toSend){ clientSocketOut!!.write(nowMsg.toByteArray(Charsets.UTF_8).size.toString().toByteArray(Charsets.UTF_8)) clientSocketOut!!.flush() clientSocketOut!!.write(nowMsg.toByteArray(Charsets.UTF_8)) clientSocketOut!!.flush() } toSend.clear() } }
问题原因
BufferedReader.readLine()的特性是必须读取到换行符\n或流结束才会返回,但Python服务端返回的字符串"Sendet "末尾没有换行符,导致客户端readLine()一直处于阻塞等待状态,直到超时或流被关闭。
而ready()仅判断当前流是否有可读数据,不会等待,所以当服务端发送完数据后ready()返回true,此时调用readLine()能读取到已发送的内容,但这只是巧合——如果服务端返回的内容未被一次性传输完成,依然会出现阻塞。
解决方案
方案1:服务端添加换行符(最直接)
修改Python服务端的发送逻辑,在返回字符串末尾加上换行符,让readLine()能识别为完整一行:
toSendTry = "Sendet \n" connection.send(bytes(toSendTry,'UTF-8'))
方案2:客户端改用非行读取方式
如果无法修改服务端,可放弃readLine(),直接读取流中所有可用字节:
val inputStream = clientSocketIn!! val buffer = ByteArray(1024) val bytesRead = inputStream.read(buffer) if (bytesRead > 0) { val receivedMsg = String(buffer, 0, bytesRead, Charsets.UTF_8) recived.add(receivedMsg) }
若服务端返回的消息长度固定,也可根据约定长度精准读取。
方案3:保留ready()但配合全量读取
继续使用ready()判断,但改用readText()读取所有可用字符(注意:若Socket保持长连接,readText()会一直阻塞到流结束,需结合消息边界约定使用):
var tmp = clientSocketIn!!.bufferedReader(Charsets.UTF_8) if(tmp.ready()){ val receivedMsg = tmp.readText() recived.add(receivedMsg) }
额外建议
- 确保Socket长连接期间未被意外关闭,通信双方需保持连接稳定性。
- 调整客户端循环逻辑,避免发送和接收的时序冲突。
- Android的AsyncTask已被官方废弃,建议改用Coroutine协程或OkHttp等现代网络框架实现异步通信。
内容的提问来源于stack exchange,提问作者Atom
相关产品推荐
相关产品推荐

