代码之家  ›  专栏  ›  技术社区  ›  Android Eve

从GetAdaptersAddresses()获取IP地址字符串?

  •  7
  • Android Eve  · 技术社区  · 15 年前

    GetAdaptersAddresses()

    typedef struct _IP_ADAPTER_UNICAST_ADDRESS {
      union {
        struct {
          ULONG Length;
          DWORD Flags;
        } ;
      } ;
      struct _IP_ADAPTER_UNICAST_ADDRESS *Next;
      SOCKET_ADDRESS                     Address;
      IP_PREFIX_ORIGIN                   PrefixOrigin;
      IP_SUFFIX_ORIGIN                   SuffixOrigin;
      IP_DAD_STATE                       DadState;
      ULONG                              ValidLifetime;
      ULONG                              PreferredLifetime;
      ULONG                              LeaseLifetime;
      UINT8                              OnLinkPrefixLength;
    } IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS;
    

    唯一一个似乎暗示人类可读IP地址字符串的字段是address,它是一个SOCKET_address结构,定义如下:

    typedef struct _SOCKET_ADDRESS {
      LPSOCKADDR lpSockaddr;
      INT        iSockaddrLength;
    } SOCKET_ADDRESS, *PSOCKET_ADDRESS;
    

    反过来,它使用另一个结构SOCKADDR,定义为:

    抱歉,在这里发帖太复杂了,因为它取决于IPv4和IPv6以及Windows版本。。。下面是定义的链接:

    http://msdn.microsoft.com/en-us/library/ms740496%28v=VS.85%29.aspx

    如果你还没有像我一样晕眩,并在这个定义迷宫中继续,你可能会注意到检索IP地址的良好的旧虚线字符串样式是一个噩梦,因为它过去更容易使用 GetAdaptersInfo() .

    我的问题是:有没有 真正地

    3 回复  |  直到 15 年前
        1
  •  6
  •   Steve Townsend    15 年前

    你可以用 GetIpAddrTable returned data structure 包含一个双字 dwAddr 那是IPv4地址。第一个链接上的示例代码应该显示您想要什么。简短的摘录向您展示我的意思:

    if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) != NO_ERROR ) { 
        printf("GetIpAddrTable failed with error %d\n", dwRetVal);
        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),       // Default language
                          (LPTSTR) & lpMsgBuf, 0, NULL)) {
            printf("\tError: %s", lpMsgBuf);
            LocalFree(lpMsgBuf);
        }
        exit(1);
    }
    
    printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
    for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
        printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
        IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
        printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr) );
    

    这个 IP_ADAPTER_UNICAST_ADDRESS 包含 SOCKET_ADDRESS Address ,依次包含 LPSOCKADDR 在lpSockAddr中-可以使用 WSAAddressToString

        2
  •  4
  •   Will Bickford    13 年前

    查看有关 SOCKADDR . 这使我们找到了 SOCKADDR_STORAGE

    引用sockaddr文档:

    严格解释 成为 指向sockaddr结构的指针。结构被解释 在不同的住址家庭背景下是不同的。

    sockaddr_in* address = (sockaddr_in*) temp->Address.lpSockaddr;
    uint32_t ipv4 = address->sin_addr.S_un.S_addr;
    // First octet:  address->sin_addr.S_un.S_un_b.s_b1
    // Second octet: address->sin_addr.S_un.S_un_b.s_b2
    // Third octet:  address->sin_addr.S_un.S_un_b.s_b3
    // Fourth octet: address->sin_addr.S_un.S_un_b.s_b4
    

    我可以想象,在给定结构定义(复制如下)的情况下,您还可以用类似的方式为ipv6转换地址。

    struct sockaddr {
            ushort  sa_family;
            char    sa_data[14];
    };
    
    struct sockaddr_in {
            short   sin_family;
            u_short sin_port;
            struct  in_addr sin_addr;
            char    sin_zero[8];
    };
    
    struct sockaddr_in6 {
            short   sin6_family;
            u_short sin6_port;
            u_long  sin6_flowinfo;
            struct  in6_addr sin6_addr;
            u_long  sin6_scope_id;
    };
    
        3
  •  0
  •   Alex    8 年前

    你可以简单地通过 _SOCKET_ADDRESS.lpSockaddr _SOCKET_ADDRESS.iSockaddrLength 作为 lpsaAddress dwAddressLength 参数到 WSAAddressToString 功能。 wsaa地址字符串 会为你做必要的转化,不需要深入挖掘。

    function SOCKET_ADDRESS_ToString(const Addr: SOCKET_ADDRESS): String;
    var
      Len: DWORD;
    begin
      if (Addr.lpSockaddr = nil) or (Addr.iSockaddrLength <= 0) then
      begin
        Result := '';
        Exit;
      end;
      Len := 0;
      WSAAddressToString(Addr.lpSockaddr, Addr.iSockaddrLength, nil, nil, Len);
      SetLength(Result, Len);
      if WSAAddressToString(Addr.lpSockaddr, Addr.iSockaddrLength, nil, PChar(Result), Len) = 0 then
        SetLength(Result, Len - 1)
      else
        Result := '';
    end;