2013-08-15 3 views
2

나는 내 델파이 2006호스트 이름에 대해 DNS에서 IP 주소를 얻는 방법은 무엇입니까?

GetIP('server-name') 또는 GetIP('google.com')를 사용하지만 지금 나는 그것이 작동하지 않습니다 Delphi-XE3에 그것을 시도하고 있다는 경우 IP 주소를 검색하여이 기능을 가지고있다. 어떤 아이디어?

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; 

결과가 델파이의 두 버전 사이의 큰 차이는 항상 '0.0.0.0'

+0

'R'의 다른 매개 변수를 확인 했습니까? 그들은 무효로합니까? – mg30rg

+1

'HostName' 매개 변수 유형을'AnsiString'으로 변경하십시오. – TLama

+0

@tlama 그것이 효과가있다! 그게 무슨 상관이야!? – PSyLoCKe

답변

8

때문에 R가 할당되지 않는 것 같다 현대 델파이는 기본적으로 넓은 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 비트 인코딩에 의해 제약받는 것은 수치스럽지 않습니까?

요즘 호스트 이름을 주소로 변환하는 데 권장되는 기능은 유니 코드 기능 GetAddrInfoW입니다.

+2

@TLama는 어떤 이유로이 내용을 답으로 쓰지 않았습니다. 질문에 답이 필요합니다. 대답이 없으면 묻는 사람은 아무 것도 받아 들일 수 없습니다. 그러므로 내 대답. –

0

이것은 winsocks2 및 유니 코드 지원을 사용하여 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; 
관련 문제