编码/解码十六进制数据包

时间:2012-06-24 21:13:51

标签: c# hex ascii packet

我想发送这个十六进制数据包:

00 38 60 dc 00 00 04 33  30 3c 00 00 00 20 63 62 
39 62 33 61 36 37 34 64  31 36 66 32 31 39 30 64 
30 34 30 63 30 39 32 66  34 66 38 38 32 62 00 06 
35 2e 31 33 2e 31 00 00  02 3c

所以我构建了字符串:

string packet = "003860dc0000" + textbox1.text+ "00000020" + textbox2.text+ "0006" + textbox3.text;

然后将其“转换”为ascii:

conn_str = HexString2Ascii(packet);

然后我发送数据包......但我有这个:

00 38 60 **c3 9c** 00 00 04 33  30 3c 00 00 00 20 63 
62 39 62 33 61 36 37 34 64  31 36 66 32 31 39 30 
64 30 34 30 63 30 39 32 66  34 66 38 38 32 62 00 
06 35 2e 31 33 2e 31 00 00  02 3c **0a**

为什么? 谢谢! 附: 功能是:

private string HexString2Ascii(string hexString)
{
     byte[] tmp;
     int j = 0;
     int lenght;
     lenght=hexString.Length-2;
     tmp = new byte[(hexString.Length)/2];
     for (int i = 0; i <= lenght; i += 2)
     {
         tmp[j] =(byte)Convert.ToChar(Int32.Parse(hexString.Substring(i, 2), System.Globalization.NumberStyles.HexNumber));
         j++;
     }
     return Encoding.GetEncoding(1252).GetString(tmp);
}

编辑: 如果我直接在字节中转换,十六进制数据包编码为字符串:

00000000  30 30 33 38 36 30 64 63  30 30 30 30 30 34 33 33 003860dc 00000433
00000010  33 30 33 43 30 30 30 30  30 30 32 30 33 34 33 32 303C0000 00203432
00000020  36 33 36 33 33 35 33 39  33 32 33 34 36 36 33 39 63633539 32346639
00000030  36 33 33 39 33 31 33 39  33 30 33 36 33 33 36 35 63393139 30363365
00000040  33 35 36 33 36 35 36 35  36 35 33 31 33 39 33 38 35636565 65313938
00000050  36 33 33 31 36 34 33 34  36 33 33 30 30 30 30 36 63316434 63300006
00000060  33 35 32 65 33 31 33 33  32 65 33 31 30 30 30 30 352e3133 2e310000
00000070  30 32 33 43                                      023C

1 个答案:

答案 0 :(得分:2)

<强> You cannot convert raw binary data to string data and expect things to just work。他们不一样。当你混淆角色编码时尤其如此。

C#字符不是ASCII字符。它们是Unicode字符,由Unicode代码点表示。然后当您转身并将这些字符写出来时,您需要指定要写出的数据类型。当您使用Encoding.GetEncoding(1252)将字节数组读入字符串时,您将获得与代码页1252对应的字符,其中0xdcÜ

但是当您的字符串被转换回字节以通过网络发送时,它将被写为UTF-8。在UTF-8中,UTF-00DC不能编码为单个字节,因为该字节值用于指示多字节序列的开始。相反,它被编码为多字节序列0xc3 0x9c。就C#而言,这两个值是相同的字符。 (我不知道额外的0x0a来自哪里,但我的猜测是来自你的一个文本框和/或你的过程的其他部分的错误换行符。)

目前还不清楚你究竟想要做什么,但我怀疑你正在转换方式太多次才能正常运作。如果您知道要发送的字节序列,为什么不直接将其编码为byte []?例如,使用MemoryStream并将所需的常量字节写入其中。

要从文本框中获取值,要将十六进制数字字符串“转换”为ASCII字符串的原始代码具有正确的想法。您只需要在有字节数组的位置停止,因为最终字节数组您想要的

public byte[] GetBytesFrom(string hex)
{
    var length = hex.Length / 2;
    var result = new byte[length];
    for (var i = 0; i < length; i++)
    {          
      result[i] = byte.Parse(hex.Substring(i, 2), NumberStyles.HexNumber);
    }

    return result;
}

// Variable portions of packet structure.
var byte[] segment2 = GetBytesFrom(textbox1.Text);
var byte[] segment4 = GetBytesFrom(textbox2.Text);
var byte[] segment6 = GetBytesFrom(textbox3.Text);

MemoryStream output = new MemoryStream();
output.Write(new[] { 0x00, 0x38, 0x60, 0xdc, 0x00, 0x00 }, 0, 6);
output.Write(segment2, 0, segment2.Length);
output.Write(new[] { 0x00, 0x00, 0x00, 0x20 }, 0, 4);
output.Write(segment4, 0, segment4.Length);
output.Write(new[] { 0x00, 0x06 }, 0, 2);
output.Write(segment6, 0, segment6.Length);

从这里开始,您可以使用MemoryStream.CopyTo()将其复制到另一个流,或MemoryStream.Read()将整个数据包读入新的字节数组,或MemoryStream.GetBuffer()获取底层缓冲区(虽然最后一个很少你想要的 - 它包括未使用的填充字节)