Как отправить двоичный поток из Java в C # через Tcp? - PullRequest
0 голосов
/ 06 мая 2019

У меня есть c # сервер .Мне нужно подключить к нему клиент Java и заставить его взаимодействовать.

Ниже приведен код C # на стороне клиента:

string Host = "localhost";
int Port = 2000;

TcpClient Tcp = new TcpClient(Host, Port);

NetworkStream stream = Tcp.GetStream();
reader = new BinaryReader(stream);
writer = new BinaryWriter(stream);

writer.Write("Hello");
string str = reader.ReadString();

Каким будет Java-эквивалент этого кода?

Я написал следующее:

    InetAddress ip = InetAddress.getByName("localhost"); 

    int PORT_NO = 2000; 
    Socket socket = new Socket(ip, PORT_NO); 

    // obtaining input and out streams 
    DataInputStream reader = new DataInputStream(socket.getInputStream()); 
    DataOutputStream writer = new DataOutputStream(socket.getOutputStream());

    writer.writeChars("Hello");
    String str = reader.readUTF();

Но мой код Java не работает.

Сервер работает нормально.Сервер, кажется, не получает строку, отправленную клиентом Java.

Как я могу делать то, что мне нужно?

.

Редактировать: Я использовал следующий код на сервере C # в соответствии с предложением @ van dench .Теперь даже клиенты C # перестали работать.

write ...

            byte[] strBytes = Encoding.UTF8.GetBytes(str);
            byte[] lenBytes = BitConverter.GetBytes(strBytes.Length);
            Array.Reverse(lenBytes);
            writer.Write(lenBytes);
            writer.Write(strBytes);
            writer.Flush(); 

read ...

            byte[] lenBytes = reader.ReadBytes(4);
            Array.Reverse(lenBytes);
            int len = BitConverter.ToInt32(lenBytes, 0);
            byte[] bytes = reader.ReadBytes(len);
            string str = Encoding.UTF8.GetString(bytes);

Ответы [ 2 ]

3 голосов
/ 06 мая 2019

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);
1 голос
/ 06 мая 2019

Проблема в том, что вы используете методы ReadString и Write в вашем коде на c #. Они используют формат с префиксом длины, о котором Java понятия не имеет.

https://docs.microsoft.com/en-us/dotnet/api/system.io.binarywriter.write?redirectedfrom=MSDN&view=netframework-4.8#System_IO_BinaryWriter_Write_System_String_

Префикс длины означает, что этот метод сначала записывает длину строки в байтах при кодировании с текущей кодировкой экземпляра BinaryWriter в поток. Это значение записывается как целое число без знака. Затем этот метод записывает столько байтов в поток.

Например, строка «A» имеет длину 1, но при кодировании с UTF-16; длина составляет 2 байта, поэтому значение, записанное в префиксе, равно 2, а в поток записывается 3 байта, включая префикс.

https://docs.microsoft.com/en-us/dotnet/api/system.io.binaryreader.readstring?view=netframework-4.8

...