web-dev-qa-db-ja.com

C#で2バイトをShortに変換する

実際のサーバーのポート値を取得できるように、2バイトを符号なしshortに変換しようとしています。私はこれをReply Formatの下の protocol specification に基づいています。これに BitConverter.ToUint16() を使用してみましたが、問題は期待された値をスローしないようです。実装例については、以下を参照してください。

int bytesRead = 0;

while (bytesRead < ms.Length)
{
    int first = ms.ReadByte() & 0xFF;
    int second = ms.ReadByte() & 0xFF;
    int third = ms.ReadByte() & 0xFF;
    int fourth = ms.ReadByte() & 0xFF;
    int port1 = ms.ReadByte();
    int port2 = ms.ReadByte();
    int actualPort = BitConverter.ToUInt16(new byte[2] {(byte)port1 , (byte)port2 }, 0);
    string ip = String.Format("{0}.{1}.{2}.{3}:{4}-{5} = {6}", first, second, third, fourth, port1, port2, actualPort);
    Debug.WriteLine(ip);
    bytesRead += 6;
}

1つのサンプルデータがあり、2つのバイト値に対して、105と135があるとします。変換後の予想ポート値は27015ですが、代わりにBitConverterを使用して34665の値を取得します。

私はそれを間違った方法で行っていますか?

26
Rafael Ibasco

BitConverter呼び出しの値を逆にすると、期待どおりの結果が得られます。

int actualPort = BitConverter.ToUInt16(new byte[2] {(byte)port2 , (byte)port1 }, 0);

リトルエンディアンアーキテクチャでは、下位バイトが配列の2番目である必要があります。 lasseespeholtがコメントで指摘しているように、ビッグエンディアンアーキテクチャでは順序を逆にする必要があります。 BitConverter.IsLittleEndian プロパティで確認できます。または、 IPAddress.HostToNetworkOrder を使用する方が全体的に優れたソリューションとなる場合があります(値を最初に変換してから、エンディアンに関係なくバイトを正しい順序で配置するためにそのメソッドを呼び出します)。

28
Mark Wilkins

BitConverterは正しいことを行っています。ローバイトとハイバイトが混ざっているだけです。ビットシフトを手動で使用して確認できます。

byte port1 = 105;
byte port2 = 135;

ushort value = BitConverter.ToUInt16(new byte[2] { (byte)port1, (byte)port2 }, 0);
ushort value2 = (ushort)(port1 + (port2 << 8)); //same output
9
BrokenGlass

リトルエンディアンとビッグエンディアンの両方のアーキテクチャで作業するには、次のようなことを行う必要があります。

if (BitConverter.IsLittleEndian)
    actualPort = BitConverter.ToUInt16(new byte[2] {(byte)port2 , (byte)port1 }, 0);
else
    actualPort = BitConverter.ToUInt16(new byte[2] {(byte)port1 , (byte)port2 }, 0);
7
Andrei Pana