You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 23:55:26