7

Java で記述されたサーバーに C# クライアントを記述しようとしています。サーバーは、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

ここで誰もがすでに指摘しているように、この問題は、C#アプリケーションがリトルエンディアンの順序でintを送信するのに対し、Javaアプリはネットワークの順序(ビッグエンディアン)でintを送信することが原因である可能性があります。ただし、C#アプリでバイトを明示的に再配置する代わりに、正しい方法は、ホストからネットワークの順序(htonなど)に変換するための組み込み関数に依存することです。これにより、コードを実行しても正常に機能し続けます。ビッグエンディアンのマシンで。

一般に、このような問題のトラブルシューティングを行う場合、netcatやwiresharkなどのツールを使用して正しいトラフィック(たとえば、JavaからJavaへ)を記録し、それを誤ったトラフィックと比較して、どこで問題が発生しているかを確認すると便利です。追加の利点として、netcatを使用して、キャプチャーされた/事前に記録された要求をサーバーに挿入したり、キャプチャーされた/事前に記録された応答をクライアントに挿入したりすることもできます。言うまでもなく、コードの修正を開始する前に、ファイル内の要求/応答を変更して結果をテストすることもできます。

于 2008-09-18T14:32:24.417 に答える
2

簡単ですが、エンディアンは確認しましたか?データを送信したエンディアンと受信しているエンディアンが一致していない可能性があります。

于 2008-09-18T13:01:15.757 に答える
1

大量のデータを交換する場合は、int をネットワーク順に読み書きできる 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() という 2 つの静的ヘルパー メソッドがあります。ストリーム上で 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 に答える