如何从DNS获取主机名的IP地址?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何从DNS获取主机名的IP地址?相关的知识,希望对你有一定的参考价值。
我有这个功能,如果我在我的Delphi 2006中使用GetIP('server-name')
或GetIP('google.com')
,则检索IP地址。
但是现在我在Delphi-XE3
上尝试它它不起作用。有任何想法吗?
function GetIP(const HostName: string): string;
var
WSAData: TWSAData;
R: PHostEnt;
A: TInAddr;
begin
Result := IPNULL; // '0.0.0.0'
WSAStartup($101, WSAData);
R := Winsock.GetHostByName(PAnsiChar(HostName));
if Assigned(R) then
begin
A := PInAddr(r^.h_Addr_List^)^;
Result := string(WinSock.inet_ntoa(A));
end;
end;
似乎R
没有被分配,因为结果总是'0.0.0.0'
答案
这两个版本的Delphi之间的最大区别在于,现代Delphi本身使用宽UTF-16编码字符串,旧版本使用ANSI编码字符串。
许多API函数都有宽版本和ANSI版本。但是你在Winsock中调用的函数只能坚持8位。
您可以通过显式使用8位文本编码使您的代码像以前一样工作。
function GetIP(const HostName: string): string;
var
WSAData: TWSAData;
R: PHostEnt;
A: TInAddr;
begin
Result := IPNULL; // '0.0.0.0'
WSAStartup($101, WSAData);
R := Winsock.GetHostByName(PAnsiChar(AnsiString(HostName)));
if Assigned(R) then
begin
A := PInAddr(r^.h_Addr_List^)^;
Result := WinSock.inet_ntoa(A);
end;
end;
现在,细心的读者会说:
如果主机名具有非ASCII字符怎么办?受这些相当微弱的固定长度8位编码约束不是一种耻辱吗?
那么,现在将主机名转换为地址的推荐功能是Unicode函数GetAddrInfoW。
另一答案
这是我使用winsocks2和unicode支持在XE3-XE7上解析IP地址的自包含示例。
由于套接字支持在每次调用时都被初始化并取消初始化,因此它不具有高性能,但重构是微不足道的。
此外,请注意,它没有经过优化以便于维护。
uses
Winapi.Winsock2;
type
PAddrInfo = ^TAddrInfo;
TAddrInfo = packed record
ai_flags: integer;
ai_family: integer;
ai_socktype: integer;
ai_protocol: integer;
ai_addrlen: NativeInt;
ai_canonname: PCHAR;
ai_addr: PSOCKADDR;
ai_next: PAddrInfo;
end;
function GetAddrInfo(const nodeName: PCHAR; const serviceName : PChar; const hints: PAddrInfo; var result: PAddrInfo): integer; stdcall; external 'ws2_32.dll' name 'GetAddrInfoW';
procedure FreeAddrInfo(const addrInfo: PAddrInfo); stdcall; external 'ws2_32.dll' name 'FreeAddrInfoW';
function ResolveIpAddress(const hostName: string; const ipv6: boolean): string;
const
BUFFER_SIZE = 32768;
var
data: TWSAData;
error: integer;
requestError: integer;
r: PAddrInfo;
s: string;
hints: TAddrInfo;
buffer: TArray<byte>;
length: DWORD;
begin
error:= WSAStartup(MAKEWORD(2, 2), data);
try
if (error = 0) then
begin
r:= nil;
try
ZeroMemory(@hints, sizeof(TAddrInfo));
if (ipv6) then
hints.ai_family:= AF_INET6
else
hints.ai_family:= AF_INET;
requestError:= GetAddrInfo(PCHAR(hostName), nil, @hints, r);
if (requestError = 0) then
begin
length:= BUFFER_SIZE;
SetLength(buffer, BUFFER_SIZE);
if (WSAAddressToString(r.ai_addr^, r.ai_addrlen, nil, @buffer[0], length) = 0) then
begin
setLength(buffer, length * 2);
s:= TUnicodeEncoding.Unicode.GetString(@buffer[0]);
exit(s);
end
else
exit('0.0.0.0');
end
else
exit('0.0.0.0');
finally
FreeAddrInfo(r);
end;
end
finally
if (error = 0) then
WSACleanup();
end;
end;
以上是关于如何从DNS获取主机名的IP地址?的主要内容,如果未能解决你的问题,请参考以下文章