Difference between GetHostEntry and GetHostByName?
-
13-11-2019 - |
문제
On MSDN it mentions GetHostByName
is obsolete. The replacement is GetHostEntry
. What are their difference?
해결책
It looks like GetHostEntry does a little more error checking and also supports Network Tracing
GetHostByName Decompiled:
public static IPHostEntry GetHostByName(string hostName)
{
if (hostName == null)
throw new ArgumentNullException("hostName");
Dns.s_DnsPermission.Demand();
IPAddress address;
if (IPAddress.TryParse(hostName, out address))
return Dns.GetUnresolveAnswer(address);
else
return Dns.InternalGetHostByName(hostName, false);
}
GetHostEntry Decompiled:
public static IPHostEntry GetHostEntry(string hostNameOrAddress)
{
if (Logging.On)
Logging.Enter(Logging.Sockets, "DNS", "GetHostEntry", hostNameOrAddress);
Dns.s_DnsPermission.Demand();
if (hostNameOrAddress == null)
throw new ArgumentNullException("hostNameOrAddress");
IPAddress address;
IPHostEntry ipHostEntry;
if (IPAddress.TryParse(hostNameOrAddress, out address))
{
if (((object) address).Equals((object) IPAddress.Any) || ((object) address).Equals((object) IPAddress.IPv6Any))
throw new ArgumentException(SR.GetString("net_invalid_ip_addr"), "hostNameOrAddress");
ipHostEntry = Dns.InternalGetHostByAddress(address, true);
}
else
ipHostEntry = Dns.InternalGetHostByName(hostNameOrAddress, true);
if (Logging.On)
Logging.Exit(Logging.Sockets, "DNS", "GetHostEntry", (object) ipHostEntry);
return ipHostEntry;
}
다른 팁
Firstly, it is important to recognize that these are wrappers of the UNIX socket library, which exposes functions inet_aton
(equivalent to IPAddress.Parse
), gethostbyname
(wrapped by Dns.GetHostByName
) and gethostbyaddr
(wrapped by Dns.GetHostByAddress
). Microsoft subsequently added the Dns.GetHostEntry
utility function based on these.
After pondering the philosophical difference between Dns.GetHostByName
and Dns.GetHostEntry
, I've come to the conclusion that Microsoft decided that the primary API they expose for DNS lookups should be trying to return only actual DNS entries.
At the UNIX sockets level, gethostbyname
can take either an IP address or a host name. It is explicitly documented as parsing the IP address if that's what you supply. But it is also explicitly documented as only supporting IPv4 addresses. As such, developers are encouraged to use the function getaddrinfo
instead, which does a more complex look-up involving the service you want to connect to as well, and which supports address families other than IPv4.
Microsoft took a different approach in their wrapper. They still consider GetHostByName
to be deprecated, but instead of tying the look-up to a services database, they decided to create a function that returns the actual physical DNS host entry you ask for. It's not enough that you perhaps supply a string with a valid address in it, if there's no DNS entry then GetHostEntry
will fail, because that is its entire purpose. Thus, if you pass a host name into GetHostEntry
, it performs a forward DNS lookup, and if you pass an IP address into GetHostEntry
, it performs a reverse DNS lookup. Either way, the returned structure will tell you both the DNS entry name and the associated address -- but if there is no associated entry, the only thing you get back is an error.
If you're looking to handle user input that supplies a target for connection, GetHostEntry
is not really suitable, because if the user types in an ad hoc IP address, it may fail to resolve it even though, since it's an IP address, you have everything you need to make a connection. GetHostByName
is exactly the function you need in this case, but Microsoft have chosen to deprecate it. Given the deprecation, the idiom is going to be to replicate the "try to parse first" approach that @Faisai Mansoor showed in the decompiled GetHostByName
function:
// Microsoft's internal code for GetHostByName:
if (IPAddress.TryParse(hostName, out address))
return Dns.GetUnresolveAnswer(address);
else
return Dns.InternalGetHostByName(hostName, false);
This uses internal implementation details of the Dns
class, but the spirit of it is easy to replicate in your own code, e.g.:
if (!IPAddress.TryParse(userInput, out var addressToWhichToConnect))
addressToWhichToConnect = Dns.GetHostEntry(userInput).AddressList.First();