7

我正在尝试将 C# 客户端写入用 Java 编写的服务器。服务器需要一个 4 字节(Java 中的 DataInputStread readInt())消息头,后跟实际消息。

我对 C# 完全陌生,如何将此消息头发送到 Java 服务器?我尝试了几种方法(主要是在没有深入了解 C# 语言的情况下反复试验),但没有任何效果。Java 端的消息长度不正确(非常大)。

4

6 回答 6

11

正如其他海报所指出的那样,它是字节序。

Java DataInputStream期望数据是大端(网络字节顺序)。从 Mono 文档(对于BinaryWriter 等等价物)来看,C# 倾向于小端(Win32/x86 的默认设置)。

因此,当您使用标准类库将 32 位 int '1' 更改为字节时,它们会产生不同的结果:

//byte hex values
Java: 00 00 00 01
  C#: 01 00 00 00

您可以更改在 C# 中编写 int 的方式:

private static void WriteInt(Stream stream, int n) {
    for(int i=3; i>=0; i--)
    {
        int shift = i * 8; //bits to shift
        byte b = (byte) (n >> shift);
        stream.WriteByte(b);
    }
}

编辑:

一种更安全的方法是:

private static void WriteToNetwork(System.IO.BinaryWriter stream, int n) {
    n = System.Net.IPAddress.HostToNetworkOrder(n);
    stream.Write(n);
}
于 2008-09-18T14:22:41.053 回答
2

As everyone here has already pointed out, the issue is most likely caused by the C# application sending ints in little-endian order whereas the Java app expects them in network order (big-endian). However, instead of explicitly rearranging bytes in the C# app, the correct way is to rely on built-in functions for converting from host to network order (htons and the likes) -- this way your code will continue working just fine even when run on a big-endian machine.

In general, when troubleshooting such issues, I find it useful to record the correct traffic (e.g., Java to Java in your case) using tools like netcat or wireshark, and then compare it to the incorrect traffic to see where it's going wrong. As an added benefit, you can also use netcat to inject the captured/prerecorded requests into the server or inject captured/prerecorded responses into the client. Not to mention that you can also modify the requests/responses in a file and test the results before commencing with fixing the code.

于 2008-09-18T14:32:24.417 回答
2

这很简单,但你检查过字节序吗?您发送数据的字节序与您接收的字节序很容易不匹配。

于 2008-09-18T13:01:15.757 回答
1

如果您要交换大量数据,我建议您实现(或找到)一个可以按网络顺序写入和读取整数的 Stream-wrapper。但是,如果您真的只需要编写长度,请执行以下操作:

using(Socket socket = ...){
  NetworkStream ns = new NetworkStream(socket);      
  ns.WriteByte((size>>24) & 0xFF);
  ns.WriteByte((size>>16) & 0xFF);
  ns.WriteByte((size>>8)  & 0xFF);
  ns.WriteByte( size      & 0xFF);
  // write the actual message
}
于 2008-09-18T13:12:37.290 回答
0

我不知道 C#,但你只需要这样做:

out.write((len >>> 24) & 0xFF);
out.write((len >>> 16) & 0xFF);
out.write((len >>>  8) & 0xFF);
out.write((len >>>  0) & 0xFF);
于 2008-09-18T13:09:31.900 回答
0

Sysetm.Net.IPAddress 类有两个静态帮助器方法:HostToNetworkOrder() 和 NetworkToHostOrder() 为您进行转换。您可以将它与流上的 BinaryWriter 一起使用以写入正确的值:

using (Socket socket = new Socket())
using (NetworkStream stream = new NetworkStream(socket))
using (BinaryWriter writer = new BinaryWriter(stream))
{
    int myValue = 42;
    writer.Write(IPAddress.HostToNetworkOrder(myValue));
}
于 2008-09-18T14:48:09.200 回答