もちろん、これはエンディアンと関係があることを私は知っています。Javaはビッグエンディアンであり、C#はリトルエンディアンであることを私は知っています。
文字列を外部システムに送信するJavaで動作するプログラムがあります。重要なのは、文字列の長さを表す文字列の先頭で2バイトのヘッダーを使用する必要があるということです。
この2バイトのヘッダーでは、最初のバイトは文字列が255文字を超えているかどうかを示すだけで、超えていない場合は常に0です。ただし、2番目のバイト(C#では正しく取得できないバイト)は文字列の長さ。最初のバイトが0の場合(ほとんどすべての場合)、文字列の長さ全体を表します。たとえば、226とします。
したがって、Javaには、ヘッダーを計算して元の文字列を追加するこのコードセグメントがあり、送信する最終的な文字列を取得できます。これは問題なく機能します。
コードのJava作業セグメント:
String iso_str = iso_buf.toString(); // This contains original string without header
int iso_len = iso_str.length(); // We need to know if it exceeds 255
int i, j;
i = (int)(iso_len / 256); // Always 0. It would be 1 if original string bigger than 255
j = (int)(iso_len % 256); // Length of the string (most times 226)
Integer ii = new Integer(i);
Integer jj = new Integer(j);
byte[] bmsg_0200 = new byte[iso_len + 2]; // We create an array of bytes making room for the 2 bytes header and the original string
bmsg_0200[0] = ii.byteValue(); // Header byte number one
bmsg_0200[1] = jj.byteValue(); // Header byte number two
System.arraycopy(iso_str.getBytes(), 0, bmsg_0200, 2, iso_str.length()); // Then we just copy the original string in the array after the header
String mensaje_str = new String(bmsg_0200); // Make the whole byte array into one string to send
次のような部分で:bmsg_0200 [1] = jj.byteValue(); ここで、javaは実際に機能するバイト値を取得します(jjが226の場合は-30になります)。そして、最終的なシステムはこのヘッダーを理解するため、すべてのメッセージを読み取ります。
.NET(C#)でコードを複製しようとしましたが、次のコードがあります。
コードのC#が機能しないセグメント:
int tramaISOLongitud = iso.Length; // iso contains original string without header, We need to know if it exceeds 255
int i, j;
i = (int)(tramaISOLongitud / 256); // Always 0. It would be 1 if original string bigger than 255
j = (int)(tramaISOLongitud % 256); // Length of the string (most times 226)
byte[] tramaISOBytes = new byte[tramaISOLongitud + 2]; // We create an array of bytes making room for the 2 bytes header and the original string
tramaISOBytes[0] = Convert.ToByte(i); // Header byte number one
tramaISOBytes[1] = Convert.ToByte(j); // Header byte number two
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud); // Then we just copy the original string in the array after the header
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
string tramaISOHeader = enc.GetString(tramaISOBytes); // Make the whole byte array into one string to send
最後のコードはすべてをコンパイルしますが、tramaISOBytes [1] = Convert.ToByte(j);で間違ったバイトを取得します。リトルエンディアンだからです。だから私は次のようにSystem.Net.IPAddress.HostToNetworkOrderを使用してみました:
int tramaISOLongitud = iso.Length; // iso contains original string without header, We need to know if it exceeds 255
int i, j;
i = (int)(tramaISOLongitud / 256); // Always 0. It would be 1 if original string bigger than 255
j = (int)(tramaISOLongitud % 256); // Length of the string (most times 226)
int i2 = System.Net.IPAddress.HostToNetworkOrder(i);
int j2 = System.Net.IPAddress.HostToNetworkOrder(j);
byte[] tramaISOBytes = new byte[tramaISOLongitud + 2]; // We create an array of bytes making room for the 2 bytes header and the original string
tramaISOBytes[0] = Convert.ToByte(i2); // Header byte number one
tramaISOBytes[1] = Convert.ToByte(j2); // Header byte number two
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud); // Then we just copy the original string in the array after the header
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
string tramaISOHeader = enc.GetString(tramaISOBytes); // Make the whole byte array into one string to send
しかし、j2は巨大な数(-503316480など)を取得しますが、大きすぎるために1バイトに変換できません。また、前述のヘッダーの長さが2バイトしかないため、1バイトで必要になります。何か案は?
前もって感謝します。
OK私はこれをもっと簡単な方法で説明します:
C#の場合:
int test = -10471344;
int test2 = -503316480;
int test3 = 57856;
byte b = (byte)test;
byte b2 = (byte)test2;
byte b3 = (byte)test3;
これらの行を実行すると、次のようになります。b = 80 b2 = 0 b3 = 0
したがって、(バイト)にキャストされた数値-10471344が80になるのはなぜですか。そして他のものはちょうど0を与えますか?実際、私は変数test2 = -503316480に興味があります。それを別の変数に変換したいのですが、0を取得します。なぜbを80にし、他の変数を0以外にすることはできないのでしょうか。
解決策:ジムが言ったように、私の問題はエンディアンとは何の関係もありませんでしたが(それはそれに関連するすべてだと思っていましたが)、重要な知識は、.NETの世界では文字列をバイト配列に変換することは問題ではないということです。ただし、バイト配列から文字列に戻ると、エンコーディング(ASCIIEncodingまたはUTF8Enconding)を使用する必要があるため問題が発生し、バイトが破損するために問題が発生します。
Javaでは、この種の問題はありませんでした。
つまり、これはその仕事をしたコードのブロックです:
static byte[] addHeader2(string iso)
{
int tramaISOLongitud = iso.Length;
byte highByte = (byte)(tramaISOLongitud >> 8);
byte lowByte = (byte)(tramaISOLongitud & 255);
byte[] tramaISOBytes = new byte[tramaISOLongitud + 2];
tramaISOBytes[0] = highByte;
tramaISOBytes[1] = lowByte;
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud);
return tramaISOBytes;
}
そして、そのバイト配列をそのままソケットに送信します。
あなたの助けをありがとう!