[英]How to force ipv6 or ipv4 for HttpWebRequest or WebRequest C#
Coming from node.js I can do this to tell node.js to make the request using ipv6 vs ipv4来自 node.js 我可以这样做来告诉 node.js 使用 ipv6 vs ipv4 发出请求
var http = require("http");
var options = {
hostname: "google.com",
family: 4, // set to 6 for ipv6
};
var req = http.request(options, function(res) {
.. handle result here ..
});
req.write("");
req.end();
Setting family
to 4
forces ipv4, setting it to 6
forces ipv6.将family
设置为4
强制 ipv4,将其设置为6
强制 ipv6。 Not setting it lets either work.不设置它可以让任何一个工作。
How can I do the same thing in C# (.NET 3.5)如何在 C# (.NET 3.5) 中做同样的事情
I can think of one way which is to make a DNS request myself myself for the A or AAAA records, make a direct IP request and set the host:
header.我可以想到一种方法,即自己为 A 或 AAAA 记录发出 DNS 请求,发出直接 IP 请求并设置host:
标头。 Is there a better way?有没有更好的办法?
You can use ServicePoint.BindIPEndPointDelegate .您可以使用ServicePoint.BindIPEndPointDelegate 。
var req = HttpWebRequest.Create(url) as HttpWebRequest;
req.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) =>
{
if (remoteEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
{
return new IPEndPoint(IPAddress.IPv6Any, 0);
}
throw new InvalidOperationException("no IPv6 address");
};
A few years later, a .NET 5 answer:几年后,一个 .NET 5 的答案:
Assuming you're using a HttpClient
, then you can set a ConnectCallback
on the SocketsHttpHandler
thus:假设您使用的是HttpClient
,那么您可以在SocketsHttpHandler
上设置ConnectCallback
,因此:
private static readonly HttpClient _http = new HttpClient(new SocketsHttpHandler() {
ConnectCallback = async (context, cancellationToken) => {
// Use DNS to look up the IP address(es) of the target host
IPHostEntry ipHostEntry = await Dns.GetHostEntryAsync(context.DnsEndPoint.Host);
// Filter for IPv4 addresses only
IPAddress ipAddress = ipHostEntry
.AddressList
.FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork);
// Fail the connection if there aren't any IPV4 addresses
if (ipAddress == null) {
throw new Exception($"No IP4 address for {context.DnsEndPoint.Host}");
}
// Open the connection to the target host/port
TcpClient tcp = new();
await tcp.ConnectAsync(ipAddress, context.DnsEndPoint.Port, cancellationToken);
// Return the NetworkStream to the caller
return tcp.GetStream();
}),
});
(This is setup for IPv4 only, to set for Ipv6 only change AddressFamiliy.InterNetwork to AddressFamily.InterNetworkV6) (这仅针对 IPv4 设置,仅针对 Ipv6 设置将 AddressFamily.InterNetwork 更改为 AddressFamily.InterNetworkV6)
Here is my solution based on @Moose Morals, with a little optimization on caching the IP which makes a really little gain (1ms on my professional PC but it might be higher on yours)这是我基于@Moose Morals 的解决方案,对缓存 IP 进行了一些优化,这确实带来了一点收益(在我的专业 PC 上为 1ms,但在您的 PC 上可能更高)
(search IP only when host changed) (仅在主机更改时搜索 IP)
I shortened a little bit but it works the same我缩短了一点,但它的工作原理是一样的
public class ResolveDnsOptimization
{
public static void ApplyTo(SocketsHttpHandler handler)
{
CachedAddress cachedAddress = null;
// Remove the latencies when using host name over IP address
// Changing pool connection lifetime and forcing to open them all does not work, the DNS resolution is always done.
// Source: https://stackoverflow.com/a/70475741/1529139
handler.ConnectCallback = async (context, cancellationToken) =>
{
if (cachedAddress == null || cachedAddress.Host != context.DnsEndPoint.Host)
{
// Use DNS to look up the IP address(es) of the target host and filter for IPv4 addresses only
IPHostEntry ipHostEntry = await Dns.GetHostEntryAsync(context.DnsEndPoint.Host);
IPAddress ipAddress = ipHostEntry.AddressList.FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork);
if (ipAddress == null)
{
cachedAddress = null;
throw new Exception($"No IP4 address for {context.DnsEndPoint.Host}");
}
cachedAddress = new CachedAddress() { Ip = ipAddress, Host = context.DnsEndPoint.Host };
}
TcpClient tcp = new();
await tcp.ConnectAsync(cachedAddress.Ip, context.DnsEndPoint.Port, cancellationToken);
return tcp.GetStream();
};
}
private class CachedAddress
{
public IPAddress Ip;
public string Host;
}
}
Usage :用法 :
SocketsHttpHandler handler = new SocketsHttpHandler();
ResolveDnsOptimization.ApplyTo(handler); // <- here
HttpClient client = new HttpClient(handler)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.