dns指定哪台服务器,指定哪些DNS服务器用来解决在.NET

这个代码示例展示了如何在.NET中实现自定义DNS解析,通过缓存结果提高效率。首先检查缓存,如果存在有效记录则直接返回。接着,根据提供的DNS服务器地址或端口进行查询。如果主机名是IP地址,直接处理;否则使用DNS服务器发送UDP请求获取IPHostEntry。解析响应并获取A记录,将结果存储在AddressList中。最后,将结果缓存并设置超时时间。
摘要由CSDN通过智能技术生成

在.NET标准测试的第二个代码示例:

public static async Task GetHostEntryAsync(string host, string dns = null)

{

if (string.IsNullOrEmpty(host))

{

return null;

}

//Check if any cached result exists

Tuple key = new Tuple(host, dns);

if (NetHelper._dnsCache.TryGetValue(key, out Tuple record) && record.Item2 > DateTime.Now)

{

return record.Item1;

}

//Check dns server's address or port

IPHostEntry result = null;

int dnsPort;

if (dns != null)

{

string[] blocks = dns.Split(':');

if (blocks.Length == 2 && int.TryParse(blocks[1], out dnsPort))//dns is ip v4

{

dns = blocks[0];

}

else if (blocks.Length == 9 && int.TryParse(blocks[8], out dnsPort))//dns is ip v6

{

blocks[0] = blocks[0].TrimStart('[');

blocks[7] = blocks[7].TrimStart(']');

dns = string.Format("{0}:{1}:{2}:{3}:{4}:{5}:{6}:{7}", blocks);

}

else

{

dnsPort = 53;

}

}

else

{

dnsPort = 53;

}

//Check if host is ip address

if (host[0] == '[' && host[host.Length - 1] == ']')//IPV6 address

{

host = host.Substring(1, host.Length - 2);

}

if (IPAddress.TryParse(host, out IPAddress address))

{

result = new IPHostEntry { AddressList = new IPAddress[] { address } };

}

else if (string.IsNullOrEmpty(dns))

{

result = await Dns.GetHostEntryAsync(host);

}

else

{

#region Resolve with customized dns server

IPAddress dnsAddr;

if (!IPAddress.TryParse(dns, out dnsAddr))

{

throw new ArgumentException("The dns host must be ip address.", nameof(dns));

}

using (MemoryStream ms = new MemoryStream())

{

Random rnd = new Random();

//About the dns message:http://www.ietf.org/rfc/rfc1035.txt

//Write message header.

ms.Write(new byte[] {

(byte)rnd.Next(0, 0xFF),(byte)rnd.Next(0, 0xFF),

0x01,

0x00,

0x00,0x01,

0x00,0x00,

0x00,0x00,

0x00,0x00

}, 0, 12);

//Write the host to query.

foreach (string block in host.Split('.'))

{

byte[] data = Encoding.UTF8.GetBytes(block);

ms.WriteByte((byte)data.Length);

ms.Write(data, 0, data.Length);

}

ms.WriteByte(0);//The end of query, muest 0(null string)

//Query type:A

ms.WriteByte(0x00);

ms.WriteByte(0x01);

//Query class:IN

ms.WriteByte(0x00);

ms.WriteByte(0x01);

Socket socket = new Socket(SocketType.Dgram, ProtocolType.Udp);

try

{

//send to dns server

byte[] buffer = ms.ToArray();

while (socket.SendTo(buffer, 0, buffer.Length, SocketFlags.None, new IPEndPoint(dnsAddr, dnsPort)) < buffer.Length) ;

buffer = new byte[0x100];

EndPoint ep = socket.LocalEndPoint;

int num = socket.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ep);

//The response message has the same header and question structure, so we move index to the answer part directly.

int index = (int)ms.Length;

//Parse response records.

void SkipName()

{

while (index < num)

{

int length = buffer[index++];

if (length == 0)

{

break;

}

else if (length > 191)

{

return;

}

index += length;

}

}

List addresses = new List();

while (index < num)

{

SkipName();//Seems the name of record is useless in this scense, so we just needs to get the next index after name.

byte type = buffer[index += 2];

index += 7;//Skip class and ttl

int length = buffer[index++] << 8 | buffer[index++];//Get record data's length

if (type == 0x01)//A record

{

if (length == 4)//Parse record data to ip v4, this is what we need.

{

addresses.Add(new IPAddress(new byte[] { buffer[index], buffer[index + 1], buffer[index + 2], buffer[index + 3] }));

}

}

index += length;

}

result = new IPHostEntry { AddressList = addresses.ToArray() };

}

finally

{

socket.Dispose();

}

}

#endregion

}

//Cache and return result

NetHelper._dnsCache[key] = new Tuple(result, DateTime.Now.AddMinutes(15));

#pragma warning disable CS4014

Task.Run(async() =>

{

await Task.Delay((int)TimeSpan.FromMinutes(15).TotalMilliseconds);

NetHelper._dnsCache.Remove(key);

});

#pragma warning restore CS4014

return result;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值