【问题标题】:Encoding/Decoding hex packet编码/解码十六进制数据包
【发布时间】:2012-06-26 05:31:31
【问题描述】:

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

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

【问题讨论】:

  • 显示 I/O 代码。某事正在添加换行符。
  • 为什么需要它作为 ascii?你不需要一个字节[]吗?我对您指出的第一个区别的猜测是 ASCII 没有 0xdc 的字符(它从 0x00 到 0x7f)。

标签: c# hex ascii packet


【解决方案1】:

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() 获取底层缓冲区(尽管最后一个很少见你想要什么——它包括未使用的填充字节)

【讨论】:

  • 感谢您的回复!我需要准确地发送我显示给你的十六进制数据包......如果我将我直接构建的字符串转换为字节,这将第二次转换为十六进制。
  • 我不确定您所说的“十六进制数据包”是什么意思。网络数据包只是 8 位整数值的流。在某些时候,它们都必须转换回字节。如果您尝试发送 bytes 0x00 0x38 0x60 0xdc 发送这些值会更安全,而不是尝试从字符串到整数到字符串到整数来回弹跳。
  • mmmm 上面的代码有问题。在文本框中我输入了十六进制值......所以编码是错误的。我需要直接在输出中写入文本框内容之类的东西!
  • 啊,你是对的,你问题中的原始代码正确地完成了这部分。让我更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
  • 2020-08-28
  • 2020-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-10
相关资源
最近更新 更多