从C#客户端向Java服务器发送4字节消息头

从C#客户端向Java服务器发送4字节消息头

Sending a 4 byte message header from C# client to a Java Server

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

我绝对不熟悉C#,如何将这个消息头发送到Java Server? 我尝试了几种方法(大多数情况下都是反复试验,而又不深入C#语言),但没有任何效果。 Java端的消息长度不正确(很大)。


正如其他张贴者所指出的那样,它是按字节顺序排列的。

Java DataInputStream期望数据为大端(网络字节顺序)。从Mono文档(对于像BinaryWriter这样的对等物)来看,C#倾向于低位优先(Win32 / x86的默认设置)。

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

1
2
3
//byte hex values
Java: 00 00 00 01
  C#: 01 00 00 00

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

1
2
3
4
5
6
7
8
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);
    }
}

编辑:

一种更安全的方法是:

1
2
3
4
private static void WriteToNetwork(System.IO.BinaryWriter stream, int n) {
    n = System.Net.IPAddress.HostToNetworkOrder(n);
    stream.Write(n);
}

正如这里的每个人都已经指出的那样,此问题最有可能是由C#应用程序以低端顺序发送int引起的,而Java应用程序期望它们以网络端(大端顺序)进行发送。但是,与其在C#应用程序中显式重新排列字节,不如正确的方法是依靠内置函数从主机顺序转换为网络顺序(Hton等),这样,即使在运行时,代码也可以继续正常运行在大端机上。

通常,在对此类问题进行故障排除时,我发现使用netcat或wirehark之??类的工具记录正确的流量(例如您的情况下的Java到Java),然后将其与错误的流量进行比较以查看问题出在哪里很有用。另外一个好处是,您还可以使用netcat将捕获/预记录的请求注入服务器,或将捕获/预记录的响应注入客户端。更不用说您还可以在开始修改代码之前,修改文件中的请求/响应并测试结果。


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


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

1
2
3
4
5
6
7
8
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
}

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

1
2
3
4
5
6
7
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));
}

我不知道C#,但是您只需要做以下等效的事情:

1
2
3
4
out.write((len >>> 24) & 0xFF);
out.write((len >>> 16) & 0xFF);
out.write((len >>>  8) & 0xFF);
out.write((len >>>  0) & 0xFF);


推荐阅读