简体   繁体   English

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

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

I am trying to write a C# client to a server that is written in Java. 我正在尝试将C#客户端编写到用Java编写的服务器上。 The server expects a 4 byte (DataInputStread readInt() in Java) message header followed by the actual message. 服务器需要一个4字节(Java中的DataInputStread readInt())消息头,后跟实际消息。

I am absolutely new to C#, how can I send this message header over to the Java Server? 我是C#的新手,如何将此消息头发送到Java Server? I tried it several ways (mostly trial and error without getting too deep into the C# language), and nothing worked. 我尝试了几种方法(主要是试验和错误,而没有深入到C#语言),没有任何效果。 The Java side ended up with the incorrect (very large) message length. Java端最终得到了错误的(非常大的)消息长度。

It is, as other posters have pointed out, down to endianness. 正如其他海报所指出的那样,它一直是字节序。

The Java DataInputStream expects the data to be big-endian (network byte order). Java DataInputStream期望数据是big-endian (网络字节顺序)。 Judging from the Mono documentation (for equivalents like BinaryWriter ), C# tends toward being little-endian (the default for Win32/x86). 从Mono文档(对于像BinaryWriter这样的等价文件)来看,C#倾向于小端(Win32 / x86的默认值)。

So, when you use the standard class library to change the 32bit int '1' to bytes, they produce different results: 因此,当您使用标准类库将32位int'1'更改为字节时,它们会产生不同的结果:

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

You can alter the way you write ints in C#: 您可以改变在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);
    }
}

EDIT: 编辑:

A safer way of doing this would be: 更安全的方法是:

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

It's simple, but have you checked endianness? 这很简单,但你检查了字节顺序吗? It could easily be a mismatch between the endianness you have sent the data in and the endianness you are recieving in. 您发送数据的字节顺序与您收到的字节顺序之间很容易不匹配。

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). 正如这里的每个人都已经指出的那样,问题很可能是由于C#应用程序以小端顺序发送整数,而Java应用程序期望它们按网络顺序(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. 但是,不是在C#app中明确重新排列字节,而是正确的方法是依靠内置函数将主机转换为网络顺序(htons等) - 这样你的代码即使在运行时也能继续正常工作在一台大端机器上。

In general, when troubleshooting such issues, I find it useful to record the correct traffic (eg, 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. 通常,在对这些问题进行故障排除时,我发现使用netcat或wireshark等工具记录正确的流量(例如,Java中的Java)很有用,然后将其与不正确的流量进行比较,以查看它出错的地方。 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. 作为额外的好处,您还可以使用netcat将捕获/预先记录的请求注入服务器或将捕获/预先记录的响应注入客户端。 Not to mention that you can also modify the requests/responses in a file and test the results before commencing with fixing the code. 更不用说您还可以修改文件中的请求/响应,并在开始修复代码之前测试结果。

If you are going to be exchanging a lot of data, I would recommend implementing (or finding) a Stream-wrapper that can write and read ints in network-order. 如果您要交换大量数据,我建议实现(或查找)可以按网络顺序写入和读取整数的Stream-wrapper。 But if you really only need to write the length do something like this: 但如果你真的只需要写长度做这样的事情:

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
}

I dont know C# but you just need to do the equivalent of this: 我不知道C#,但你只需要做相同的事情:

out.write((len >>> 24) & 0xFF);
out.write((len >>> 16) & 0xFF);
out.write((len >>>  8) & 0xFF);
out.write((len >>>  0) & 0xFF);

The Sysetm.Net.IPAddress class has two static helper methods: HostToNetworkOrder() and NetworkToHostOrder() that do the conversion for you. Sysetm.Net.IPAddress类有两个静态辅助方法:HostToNetworkOrder()和NetworkToHostOrder()为您进行转换。 You can use it with a BinaryWriter over the stream to write the proper value: 您可以在流上使用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));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM