如何从字节数组中获得字符串?



我正在创建我自己的DNS服务器和主机拦截器,我想从DNS请求消息byte[]

获得主机dns message十六进制转储:

e07901000001000000000000057961686f6f03636f6d0000010001
.y...........yahoo.com.....

代码:

using System;
using System.Text;
public class Program
{
public static void Main()
{
string b64 = "4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB";
int pad = b64.Length % 4;
if (pad > 0 )
{
b64 += new string('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while(decoded[end] != 0){
end++;
}

int hostLength = end-start;
byte[] byteHost = new byte[hostLength];
Array.Copy(decoded, start, byteHost, 0, hostLength);
string host = Encoding.Default.GetString(byteHost);
Console.WriteLine(host); // yahoo♥com
}
}

问题:

  1. 是我上面的方法获得主机名正确/有效/最快?
  2. 为什么我得到奇怪的字符取代点yahoo♥com?

更改为Encoding。ASCII或编码。UTF8无效

  1. 不需要第二个数组;Encoding.GetString允许您传入偏移量和计数,因此:GetString(decoded, start, hostLength)
  2. 永远不要使用Encoding.Default;这是糟糕的命名-它应该被称为Encoding.Wrong:)找出什么编码的数据(可能是UTF-8或ASCII),和使用
  3. 您应该能够使用IndexOf找到终止'';还要考虑如果没有找到
  4. ,代码应该怎么做。

对于不寻常的字符:数据包含一个03字节,而您期望.;检查DNS协议规范,看看这是否是预期的。03ETX(文本结束)。除此之外:我不知道。

找到了答案,03不是ETX而是下一个字符串的长度,让我们看看例子

00 05 79 61 68 6F 6F 03 63 6F 6D
.  .  y  a  h  o  o  .  c  o  m

05的平均值为yahoo的长度,03com的长度

有效的主机或域名只包含44-127或[a-z0-9-.]的ASCII范围,像bücher.nu这样的域名将转换为xn--bcher-kva.nu,所以我用点.替换像03,0C,09或44以下的字节

并感谢@Marc Gravell的GetString(decoded, start, hostLength)

/*
I0sBAAABAAAAAAAABmMtcmluZwZtc2VkZ2UDbmV0AAABAAE
ldgBAAABAAAAAAAABWZwLXZwCWF6dXJlZWRnZQNuZXQAAAEAAQ
4HkBAAABAAAAAAAABXlhaG9vA2NvbQAAAQAB
*/
string b64 = "4VoBAAABAAAAAAAAIGYyNWIzNjgyMGUyNDljNGQxY2I0YzQzNGUxNjc5YTljA2Nsbwxmb290cHJpbnRkbnMDY29tAAABAAE";
int pad = b64.Length % 4;
if (pad > 0)
{
b64 += new string ('=', 4 - pad);
}
byte[] decoded = Convert.FromBase64String(b64);
int start = 13;
int end = start;
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);
Console.WriteLine(host);

编辑:微优化,基准测试与1e9或十亿循环

Convert.ToChar()finished in 00:00:04

for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
host += Convert.ToChar(decoded[end]);
end++;
}
}

VSEncoding.ASCII.GetString()跑完全程00:03:20(200秒)

for(int i =0; i<1e9; i++){
while (decoded[end] != 0)
{
if(decoded[end] < 44)
decoded[end] = 0x2e;
end++;
}
int hostLength = end - start;
string host = Encoding.ASCII.GetString(decoded, start, hostLength);

最新更新