dragzz
dragzz

Reputation: 25

Can't get Java and C# to communicate through sockets

I've been trying to create a Java and C# app that would communicate together. In this case the user sends a String from the C# side, it should display on the Java console and echo back. Unfortunately, I have only been able to establish the connection, without being able to send or receive anything.

Java code snippet:

public CommunicationThreadHandler(Socket socket, CarList carList) {
    this.socket = socket;
    this.carList = carList;
    try {
        this.in = new DataInputStream(socket.getInputStream());
        this.out = new DataOutputStream(socket.getOutputStream());
        this.writer = new Writer(out);
    } catch (IOException e) {
        System.out.println("Exception when reading or receiving data!");
        e.printStackTrace();
    }
    this.ip = socket.getRemoteSocketAddress().toString();
}

@Override
public void run() {
    while (true) {
        try {
            Gson gson = new Gson();
            String msgJson = in.readUTF();
            String msg = gson.fromJson(msgJson,String.class);
            System.out.println("Message from C# client: "+msg);
            String reply = "Server echo: "+msg;
            String replyJson = gson.toJson(reply);
            out.writeUTF(replyJson);
            if (msg.equals(Package.EXIT))
                break;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

C# snippet:

public static void StartClient()
{
    // Data buffer for incoming data.  
    byte[] bytes = new byte[1024];

    // Connect to a remote device.  
    try
    {
        // Establish the remote endpoint for the socket.  
        // This example uses port 11000 on the local computer.  
        IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);

        // Create a TCP/IP  socket.  
        Socket sender = new Socket(ipAddress.AddressFamily,
            SocketType.Stream, ProtocolType.Tcp);

        // Connect the socket to the remote endpoint. Catch any errors.  
        try
        { 
            sender.Connect(remoteEP);

            Console.WriteLine("Socket connected to {0}",
                sender.RemoteEndPoint.ToString());
            while (true)
            {
                Console.Write("Enter message to server: ");

                string message = Console.ReadLine();
                Console.WriteLine($"To be sent: {message}");

                // Encode the data string into a byte array.  
                byte[] msg = Encoding.ASCII.GetBytes(message);

                // Send the data through the socket.  
                int bytesSent = sender.Send(msg);

                // Receive the response from the remote device.  
                int bytesRec = sender.Receive(bytes);

                string msgFromServer = Encoding.ASCII.GetString(bytes, 0, bytesRec);

                if (msgFromServer.Equals("EXIT"))
                    break;

                Console.WriteLine($"Server says: {msgFromServer}");
            }
            // Release the socket.

            sender.Shutdown(SocketShutdown.Both);
            sender.Close();

        }

Upvotes: 1

Views: 587

Answers (1)

Mark Rotteveel
Mark Rotteveel

Reputation: 109239

Your problem is that you're using DataInputStream/DataOutputStream in Java, which use a Java-specific, XDR-like datatype serialization protocol. You are not using that protocol at your C# side.

Switching to using the raw input/output stream should be sufficient (although very brittle). However, notice that as you are sending raw bytes from C#, it will be impossible to tell for the recipient when the message is complete. It would be better to send the number of bytes of the message, followed by the actual message (this is what DataInputStream/DataOutputStream does, but it comes with additional considerations that you would need to correctly implement in your C# side, for example readUTF/writeUTF use a 'modified UTF-8' format instead of normal UTF-8).

The problem right now, is that you send raw bytes from C#, the readUTF() method reads the first two bytes as length, and then tries to read a message of that length. For example if C# sends "Hello" (encoded as 0x48, 0x65, 0x6c, 0x6c, 0x6f), then the Java side will read 0x48, 0x65 ("He") as "message length is 18533" and then tries to read 18533 bytes, while the actual remaining bytes are only 3 (the "llo"). This causes the input to block waiting for the remaining 18530 bytes, which never arrive.

Upvotes: 2

Related Questions