【问题标题】:Can't get Java and C# to communicate through sockets无法让 Java 和 C# 通过套接字进行通信
【发布时间】:2018-12-05 21:55:31
【问题描述】:

我一直在尝试创建一个可以一起通信的 Java 和 C# 应用程序。在这种情况下,用户从 C# 端发送String,它应该显示在 Java 控制台上并回显。不幸的是,我只能建立连接,无法发送或接收任何东西。

Java代码sn-p:

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#sn-p:

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

        }

【问题讨论】:

  • 那么你的错误是什么?
  • 您展示了 2 次尝试但没有捕获,。所以我不得不假设错误的异常处理是你缺乏调试信息的原因。这里有两篇我经常链接的关于这个问题的文章:blogs.msdn.microsoft.com/ericlippert/2008/09/10/… | codeproject.com/Articles/9538/… 除非您向我们提供有关正在发生/未发生的事情的更多信息,否则我们无法为您提供帮助。
  • 这甚至有可能是网络问题。 Java 的一个缺点是您只能阻止/取消阻止整个 Java 运行时进行网络通信。由于“Java 程序”的解释类似于批处理文件,因此您不能单独锁定/解锁它们。 .NET 没有这个问题。这是他们在使用 MSIL 复制 JavaBytecode 时真正改进的地方之一。
  • Java:不要使用 DataOutputStream/DataInputStream 与 C# 客户端通信。使用类似的东西:new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(socket.getOutputStream()), StandardCharsets.UTF_8))。您需要一个带有编码的显式 OutputStreamWriter 来获取 Writer。您不能简单地将 OutputStream 传递给 Writer 的构造函数。
  • @Christopher 实际上你可以,如果你正确使用 Java 安全管理器,但我看不出这在这个问题的上下文中是如何相关的。

标签: java c# sockets


【解决方案1】:

您的问题是您在 Java 中使用 DataInputStream/DataOutputStream,它使用特定于 Java 的、类似 XDR 的数据类型序列化协议。您没有在 C# 端使用该协议。

切换到使用原始输入/输出流应该就足够了(虽然很脆弱)。但是,请注意,当您从 C# 发送原始字节时,无法告知收件人何时消息完成。最好先发送消息的字节数,然后发送实际消息(这就是 DataInputStream/DataOutputStream 所做的,但它附带了您需要在 C# 端正确实现的其他注意事项,例如readUTF/writeUTF 使用“修改的 UTF-8”格式而不是普通的 UTF-8)。

现在的问题是,您从 C# 发送原始字节,readUTF() 方法读取前两个字节作为长度,然后尝试读取该长度的消息。例如如果C#发送“Hello”(编码为0x48、0x65、0x6c、0x6c、0x6f),那么Java端会读取0x48、0x65(“He”)为“消息长度为18533”,然后尝试读取18533字节,而实际剩余的字节只有 3 个(“llo”)。这会导致输入阻塞等待剩余的 18530 字节,这些字节永远不会到达。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-26
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    相关资源
    最近更新 更多