The DataOutput.writeUTF() https://docs.oracle.com/javase/8/docs/api/java/io/DataOutput.html#writeUTF-java.lang.String- and DataInput.readUTF() https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#readUTF--Java 中的方法在 Python 中没有任何直接等效项。正如 Javadoc 中的DataOutput.writeUTF() https://docs.oracle.com/javase/8/docs/api/java/io/DataOutput.html#writeUTF-java.lang.String- state:
将两个字节的长度信息写入输出流,随后
通过字符串中每个字符的修改后的 UTF-8 表示
s。如果 s 为 null,则抛出 NullPointerException。中的每个角色
字符串 s 被转换为一组、两个或三个字节,
取决于角色的价值。
两个长度字节按大端顺序排列。因此,读取此信息的Python程序至少必须首先读取这两个长度字节以确定后续数据的长度,然后读取那么多字节的特殊编码字符数据,最后对其进行解码。根据讨论,在 python 端对其进行解码似乎并不简单here https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html关于所使用的编码,称为“modified UTF-8”:
该格式与标准UTF-8格式的区别是
下列:
- 空字节 '\u0000' 以 2 字节格式编码,而不是 1 字节,
以便编码的字符串永远不会嵌入空值。
- 仅使用 1 字节、2 字节和 3 字节格式。
- 补充字符以代理对的形式表示。
作为我认为更容易的替代方案,在 Java 方面考虑放弃readUTf()
and writeUTF()
方法并将其替换为您自己的版本,如下所示:
public void writeUTF8(String s, DataOutput out) throws IOException {
byte [] encoded = s.getBytes(StandardCharsets.UTF_8);
out.writeInt(encoded.length);
out.write(encoded);
}
public String readUTF8(DataInput in) throws IOException {
int length = in.readInt();
byte [] encoded = new byte[length];
in.readFully(encoded);
return new String(encoded, StandardCharsets.UTF_8);
}
然后,在 python 方面,等效的代码可能是:
def recvall(sock, size):
received_chunks = []
buf_size = 4096
remaining = size
while remaining > 0:
received = sock.recv(min(remaining, buf_size))
if not received:
raise Exception('unexcepted EOF')
received_chunks.append(received)
remaining -= len(received)
return b''.join(received_chunks)
def read_utf8(sock):
len_bytes = recvall(sock, 4)
length = struct.unpack('>i', len_bytes)[0]
encoded = recvall(sock, length)
return str(encoded, encoding='utf-8')
def write_utf8(s: str, sock: socket.socket):
encoded = s.encode(encoding='utf-8')
sock.sendall(struct.pack('>i', len(encoded)))
sock.sendall(encoded)