Java DataOutputStream
и DataInputStream
кодируют строки в формате, известном как Modified UTF-8. В основном это означает, что один символ может иметь длину 1, 2 или 3 байта. Он предназначен для записи строк в более сжатой среде, предполагая, что большинство людей будут использовать символы ASCII. Старший бит в закодированных данных используется для определения, существует ли впоследствии другой байт, являющийся частью того же символа.
Как я могу сказать, C # BinaryWriter
и BinaryReader
просто кодируют необработанные данные UTF-16.
Самое простое решение - записать байтовый массив вместо строки.
В C # вам понадобится следующее:
byte[] bytes = Encoding.UTF8.GetBytes(str);
writer.Write(bytes.Length);
writer.Write(bytes);
int len = reader.ReadInt32();
byte[] bytes = reader.ReadBytes(len);
string str = Encoding.UTF8.GetString(bytes);
и на Java вам понадобится:
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
writer.writeInt(bytes.length)
writer.write(bytes, 0, bytes.length);
int len = reader.readInt();
byte[] bytes = new byte[len];
reader.read(bytes, 0, len);
String str = new String(bytes, StandardCharsets.UTF_8);
Вы можете изменить кодировку на другое, если хотите, но она должна быть одинаковой на клиенте и на сервере.
Edit:
Java предпочитает Big Endian, в то время как C # предпочитает Little Endian, из-за этого одна из длин должна быть обращена вспять. Учитывая, что порядок байтов в сети является прямым порядком байтов, я бы рекомендовал делать это на стороне C #.
byte[] lenBytes = BitConverter.GetBytes(strBytes.Length);
Array.Reverse(lenBytes);
writer.Write(lenBytes);
byte[] lenBytes = reader.ReadBytes(4);
Array.Reverse(lenBytes);
int len = BitConverter.ToInt32(lenBytes);