0

I'm unable to send a UTF-8 string from a C# server to a Java client due to an EOF error in the client. How do I properly configure the C# server? I assume the error lies there because this client works with the Java server shown below.

Java client's receive function does this (this also works if I receive from a Java server, shown below):

DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); //The constructor initialises a field, using the socket object.        
StringBuilder inputMessage = new StringBuilder();
inputMessage.append((String) dataInputStream.readUTF());

Desired C# server:

        static async Task Main(string[] args)
        {
            TcpListener server = new TcpListener(IPAddress.Any, 34567);
            server.Start();
            byte[] bytes = new byte[4096];
            byte[] responseBytes;
            using (var client = await server.AcceptTcpClientAsync()){
                using(var tcpStream = client.GetStream())
                {
                    await tcpStream.ReadAsync(bytes, 0, bytes.Length);
                    var playerNumber = Encoding.UTF8.GetString(bytes);
                    Console.WriteLine("Player " + playerNumber + " connected."); //java client to server works.

                    StringBuilder outputMessage = new StringBuilder("Some output");
                    responseBytes = Encoding.UTF8.GetBytes(outputMessage.ToString());
                    await tcpStream.WriteAsync(responseBytes, 0, responseBytes.Length); //This doesn't work...
                }
                server.Stop();
            }
        }

The error:

java.io.EOFException
    at java.base/java.io.DataInputStream.readFully(DataInputStream.java:201)
    at java.base/java.io.DataInputStream.readUTF(DataInputStream.java:613)
    at java.base/java.io.DataInputStream.readUTF(DataInputStream.java:568)
    at Client.Connection.Receive(Connection.java:26)
    at Client.Main.lambda$main$0(Main.java:30)
    at com.sun.javafx.application.PlatformImpl.lambda$startup$5(PlatformImpl.java:271)
    at com.sun.glass.ui.Application.invokeAndWait(Application.java:464)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runToolkit(QuantumToolkit.java:366)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$startup$10(QuantumToolkit.java:280)
    at com.sun.glass.ui.Application.lambda$run$1(Application.java:153)

Interestingly, a Java server doing this works:

            DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
            StringBuilder outputMessage = new StringBuilder("Some output");
            dataOutputStream.writeUTF(outputMessage.toString());
            dataOutputStream.flush();

EDIT

This is received from the working Java server. The "bytearr" contains 100 bytes that I am using for my message and 100 bytes that are 0 (they come after my message). The "chararr" correctly sees the first 100 bytes as something meaningful and the last 200 bytes as '\u0000': enter image description here enter image description here

This is received form the non-working C# server. It seems to start two bytes in compared to the correct version and also it's "chararr" contains only thousands of '\u0000': enter image description here enter image description here

saner
  • 399
  • 4
  • 13
  • 4
    lets ignore everything else and start from *first principles*... What bytes are being received, what bytes do you except. How do they differ. – TheGeneral Dec 22 '20 at 03:04
  • 3
    I don't know if this is directly related to the problem you're asking about, but ignoring the return value of `ReadAsync` is a bad idea. If you don't receive 4096 bytes (even if that much was written, TCP doesn't guarantee all of it will arrive at the same time, just that they'll be in the same order), then `Encoding.UTF8.GetString` is going to decode all 4096 bytes of the buffer and you'll get `0`s at the end. Use that return value! – madreflection Dec 22 '20 at 03:08
  • 1
    Look at what is actually sent. Wireshark may be useful. – Thorbjørn Ravn Andersen Dec 22 '20 at 03:32
  • 1
    In such cases, it's always a good idea to hit the docs and check if the methods and classes you are using are actually supposed to be doing what you think they are doing. – Fildor Dec 22 '20 at 07:51

2 Answers2

3

DataInputStream's readUTF reads a special data format, it is not a general purpose method for reading a sequence of UTF-8 bytes. Most notably, it expects an initial sequence of bytes specifying the length of the stream.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
1

I found the answer here. Changing the way the Java client reads to this, works:

byte[] buff = dataInputStream.readAllBytes();
String str = new String(buff, "UTF-8");
saner
  • 399
  • 4
  • 13