简体   繁体   中英

How to send a binary stream from Java to C# via Tcp?

I have a c# server . I need to connect a Java client to it, and make it interact.

The following is a client-side C# code:

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();

What would be the Java equivalent of this code?

I have written the following:

    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();

But, my java code isn't working.

Server is running okay. The server seems to be not receiving the string sent by Java client.

How can I do what I need?

.

Edit: I used the following code in C# server according to @van dench 's suggestion. Now, even C# clients stopped working.

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);

Java's DataOutputStream and DataInputStream encode strings in a format known as Modified UTF-8. This basically means that a single character can be either 1, 2, or 3 bytes long. It is intended to write strings in a more compressed manor assuming that most people will be using ASCII characters. The leading bit in the encoded data is used to determine if there is another byte afterwards that is part of the same character.

As best I can tell C#'s BinaryWriter and BinaryReader just encodes the raw UTF-16 data.

The easiest solution is going be write a byte array instead of a string.

In C# you're going to need the following:

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);

and in Java you will need:

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);

You can change the encoding to something else if you wish, but it has to be the same on the client and the server.

Edit:

Java prefers Big Endian while C# prefers Little Endian, because of this one of the lengths has to be reversed. Given that network byte order is big endian I would recommend doing this on the C# side.

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);

The problem is that you are using ReadString and Write methods in your c# code. They use a length-prefixed format that Java has no idea about.

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

Length-prefixed means that this method first writes the length of the string, in bytes, when encoded with the BinaryWriter instance's current encoding to the stream. This value is written as an unsigned integer. This method then writes that many bytes to the stream.

For example, the string "A" has a length of 1, but when encoded with UTF-16; the length is 2 bytes, so the value written in the prefix is 2, and 3 bytes are written to the stream, including the prefix.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM