Java客户端与Python服务端Socket通信:客户端收消息死锁求助
Java-Python Socket通信:服务端回复无法被客户端接收的问题解决
我帮你排查下这个问题,核心原因是Java客户端和Python服务端使用的字符串传输格式不兼容,导致客户端的readUTF()方法一直处于等待状态,陷入死锁。
问题根源
Java的DataOutputStream.writeUTF()和DataInputStream.readUTF()是一套成对的专属方法:
writeUTF()会先把字符串的UTF-8编码字节长度,以2字节大端序的short类型写入流中,再写入字符串的UTF-8字节;readUTF()则会先读取这2个字节获取长度,再读取对应长度的字节来解码成字符串。
而你的Python服务端直接用conn.send("bye".encode('UTF-8'))发送的是纯UTF-8字节,没有这个长度前缀。Java客户端的readUTF()一直在等待那2个长度字节,自然会卡住。
解决方案(两种可选)
方案1:修改Python服务端,适配Java的readUTF()格式
按照Java的UTF-8传输规范,先发送长度前缀,再发送字符串内容:
import socket import struct soc = socket.socket() host = "localhost" port = 2004 soc.bind((host, port)) soc.listen(5) while True: conn, addr = soc.accept() print("Got connection from", addr) # 先读取Java发送的2字节长度前缀 len_prefix = conn.recv(2) if not len_prefix: conn.close() continue # 解析大端序的short长度 msg_length = struct.unpack('!H', len_prefix)[0] # 读取对应长度的消息内容 msg = conn.recv(msg_length).decode('UTF-8') print(f"Received: {msg}") if "Hello" in msg: response = "bye" response_bytes = response.encode('UTF-8') # 先发送2字节的长度前缀(大端序) conn.send(struct.pack('!H', len(response_bytes))) # 再发送响应内容 conn.send(response_bytes) else: print("No valid message received") conn.close()
方案2:修改Java客户端,使用通用UTF-8传输格式
放弃Java的DataInputStream/DataOutputStream,改用普通的字符流,和Python的纯UTF-8传输兼容:
import java.io.*; import java.net.*; public class Client { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 2004); // 使用字符流发送UTF-8字符串,添加换行符作为结束标记 OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8"); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); writer.write("Hello\n"); writer.flush(); System.out.println("Sent first message"); // 读取服务端发送的换行结尾的字符串 String response = reader.readLine(); System.out.println("Received message: " + response); writer.close(); reader.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } }
对应的Python服务端也要调整为读取换行结尾的字符串:
import socket soc = socket.socket() host = "localhost" port = 2004 soc.bind((host, port)) soc.listen(5) while True: conn, addr = soc.accept() print("Got connection from", addr) # 读取到换行符为止,去除首尾空白 msg = conn.recv(1024).decode('UTF-8').strip() print(f"Received: {msg}") if "Hello" in msg: # 发送带换行的响应,让Java的readLine()可以识别 conn.send("bye\n".encode('UTF-8')) else: print("No valid message received") conn.close()
额外注意点
- 不管用哪种方案,处理完连接后记得调用
conn.close()关闭连接,避免资源泄漏; - 如果需要传输大文件或长消息,要注意
recv()可能不会一次性读取全部内容,需要循环读取直到获取完整数据。
内容的提问来源于stack exchange,提问作者epascolo
相关产品推荐
相关产品推荐

