【问题标题】:Sending a 4 byte message header from C# client to a Java Server从 C# 客户端向 Java 服务器发送一个 4 字节的消息头
【发布时间】:2010-09-10 16:11:12
【问题描述】:

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

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

【问题讨论】:

    标签: c# java sockets


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      我不知道 C#,但你只需要做类似的事情:

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

      【讨论】:

        【解决方案3】:

        如果您要交换大量数据,我建议您实现(或寻找)一个可以按网络顺序写入和读取整数的 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
        }
        

        【讨论】:

          【解决方案4】:

          正如其他发帖者所指出的,它是字节序。

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

          所以,当您使用标准类库将 32bit 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);
          }
          

          【讨论】:

            【解决方案5】:

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

            一般来说,在解决此类问题时,我发现使用 netcat 或 wireshark 等工具记录正确的流量(例如,Java 到 Java)很有用,然后将其与不正确的流量进行比较以查看它的去向错误的。作为一个额外的好处,您还可以使用 netcat 将捕获/预先录制的请求注入服务器或将捕获/预先录制的响应注入客户端。更不用说您还可以在开始修复代码之前修改文件中的请求/响应并测试结果。

            【讨论】:

              【解决方案6】:

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

              【讨论】:

                猜你喜欢
                • 2016-07-13
                • 1970-01-01
                • 2017-01-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-08-31
                相关资源
                最近更新 更多