c++ - GetAdaptersAddresses() 未给出正确的 IP 地址

标签 c++ c sockets visual-c++ network-programming

我正在使用 USB Internet 加密狗为我的计算机分配 IPv6 地址。当我使用ipconfig时,我可以看到分配的IPv6地址,它是一个公共(public)IP。

当我使用GetAdaptersAddresses()时,我得到了一个长链表,其中包含任播、多播和单播地址,但它们都与系统的 IP 地址不匹配。

还有其他地方可以获取系统的IP吗?我实际上想获取系统的 IP 地址,以便将其绑定(bind)到套接字。

我使用 Windows 7。

// getadaptersinfo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<WinSock2.h>
#include<iphlpapi.h>
#include<ws2tcpip.h>
#include<iostream>
#pragma comment(lib,"IPHLPAPI.lib")
#pragma comment(lib,"Ws2_32.lib")
using namespace std;

int main()
{
    cout << "\nusing getadapteraddress";
    PIP_ADAPTER_ADDRESSES p, tp;
    ULONG u;
    DWORD ret;
    p = (IP_ADAPTER_ADDRESSES*)HeapAlloc(GetProcessHeap(), 0, sizeof(IP_ADAPTER_ADDRESSES));
    u = sizeof(p);
    GetAdaptersAddresses(0, GAA_FLAG_INCLUDE_PREFIX, NULL, p, &u);
    p = (IP_ADAPTER_ADDRESSES*)HeapAlloc(GetProcessHeap(), 0, u);
    ret = GetAdaptersAddresses(0, GAA_FLAG_INCLUDE_PREFIX, NULL, p, &u);
    if (ret == NO_ERROR)
    {
        tp = p;
        while (tp)
        {
            cout << "\nlength of ip adapter address";
            tp->Length;
            cout << "\nifindex (ipv4):" << tp->IfIndex;
            cout << "\n Adapter name::" << tp->AdapterName;
            PIP_ADAPTER_UNICAST_ADDRESS pu;
            pu = tp->FirstUnicastAddress;
            int i = 0;
            cout << "\nunicast address:";
            while (pu)
            {
                i++;
                cout << "\nlength of sockaddr: " << (pu->Address).iSockaddrLength;
                if (pu->Address.lpSockaddr->sa_family == AF_INET)
                {
                    cout << "\n ipv4 addr:";
                    sockaddr_in *si = (sockaddr_in *)&(pu->Address.lpSockaddr);
                    char a[INET_ADDRSTRLEN];
                    inet_ntop(AF_INET, si, a, sizeof(a));
                    cout << a;
                }
                else if (pu->Address.lpSockaddr->sa_family == AF_INET6)
                {
                    cout << "\n ipv6 addr:";
                    sockaddr_in6 *si = (sockaddr_in6 *)&(pu->Address.lpSockaddr);
                    char a[INET6_ADDRSTRLEN];
                    inet_ntop(AF_INET6, si, a, sizeof(a));
                    cout << a;
                }
                pu = pu->Next;
            }
            cout << "\n no of unicast address" << i;
            PIP_ADAPTER_ANYCAST_ADDRESS pa;
            i = 0;
            pa = tp->FirstAnycastAddress;
            cout << "\nanycast address:"; 
            while (pa)
            {
                i++;
                cout << "\nlength of sockaddr: " << (pa->Address).iSockaddrLength;
                if (pa->Address.lpSockaddr->sa_family == AF_INET)
                {
                    cout << "\n ipv4 addr:";
                    sockaddr_in *si = (sockaddr_in *)&(pa->Address.lpSockaddr);
                    char a[INET_ADDRSTRLEN];
                    inet_ntop(AF_INET, si, a, sizeof(a));
                    cout << a;
                }
                else if (pa->Address.lpSockaddr->sa_family == AF_INET6)
                {
                    cout << "\n ipv6 addr:";
                    sockaddr_in6 *si = (sockaddr_in6 *)&(pa->Address.lpSockaddr);
                    char a[INET6_ADDRSTRLEN];
                    inet_ntop(AF_INET6, si, a, sizeof(a));
                    cout << a;
                }
                pa = pa->Next;
            }
            cout << "\n no of anycast address" << i;
            PIP_ADAPTER_MULTICAST_ADDRESS pm;
            i = 0;
            pm = tp->FirstMulticastAddress;
            cout << "\nmulticast address:";
            while (pm)
            {
                i++;
                cout << "\nlength of sockaddr: " << (pm->Address).iSockaddrLength;
                if (pm->Address.lpSockaddr->sa_family == AF_INET)
                {
                    cout << "\n ipv4 addr:";
                    sockaddr_in *si = (sockaddr_in *)&(pm->Address.lpSockaddr);
                    char a[INET_ADDRSTRLEN];
                    inet_ntop(AF_INET, si, a, sizeof(a));
                    cout << a;
                }
                else if (pm->Address.lpSockaddr->sa_family == AF_INET6)
                {
                    cout << "\n ipv6 addr:";
                    sockaddr_in6 *si = (sockaddr_in6 *)&(pm->Address.lpSockaddr);
                    char a[INET6_ADDRSTRLEN];
                    inet_ntop(AF_INET6, si, a, sizeof(a));
                    cout << a;
                }
                pm = pm->Next;
            }
            cout << "\n no of multicast address" << i;
            PIP_ADAPTER_DNS_SERVER_ADDRESS pd;
            i = 0;
            pd = tp->FirstDnsServerAddress;
            cout << "\ndns address:";
            while (pd)
            {
                i++;
                cout << "\nlength of sockaddr: " << (pd->Address).iSockaddrLength;
                if (pd->Address.lpSockaddr->sa_family == AF_INET)
                {
                    cout << "\n ipv4 addr:";
                    sockaddr_in *si = (sockaddr_in *)&(pd->Address.lpSockaddr);
                    char a[INET_ADDRSTRLEN];
                    inet_ntop(AF_INET, si, a, sizeof(a));
                    cout << a;
                }
                else if (pd->Address.lpSockaddr->sa_family == AF_INET6)
                {
                    cout << "\n ipv6 addr:";
                    sockaddr_in6 *si = (sockaddr_in6 *)&(pd->Address.lpSockaddr);
                    char a[INET6_ADDRSTRLEN];
                    inet_ntop(AF_INET6, si, a, sizeof(a));
                    cout << a;
                }
                pd = pd->Next;
            }
            cout << "\n no of dns server address" << i;
            PIP_ADAPTER_GATEWAY_ADDRESS_LH pg;
            i = 0;
            pg = tp->FirstGatewayAddress;
            cout << "\ngateway address:"; 
            while (pg)
            {
                i++;
                cout << "\nlength of sockaddr: " << (pg->Address).iSockaddrLength;
                if (pg->Address.lpSockaddr->sa_family == AF_INET)
                {
                    cout << "\n ipv4 addr:";
                    sockaddr_in *si = (sockaddr_in *)&(pg->Address.lpSockaddr);
                    char a[INET_ADDRSTRLEN];
                    inet_ntop(AF_INET, si, a, sizeof(a));
                    cout << a;
                }
                else if (pg->Address.lpSockaddr->sa_family == AF_INET6)
                {
                    cout << "\n ipv6 addr:";
                    sockaddr_in6 *si = (sockaddr_in6 *)&(pg->Address.lpSockaddr);
                    char a[INET6_ADDRSTRLEN];
                    inet_ntop(AF_INET6, si, a, sizeof(a));
                    cout << a;
                }
                pg = pg->Next;
            }
            cout << "\ngateway address:" << i;
            cout << "\n dns suffix" << tp->DnsSuffix;
            cout << "\n description" << tp->Description;
            cout << "\n friendly name" << tp->FriendlyName;
            if (tp->PhysicalAddressLength != 0)
                for (UINT i = 0; i < tp->PhysicalAddressLength; i++)
                {
                    if (i == (tp->PhysicalAddressLength - 1))
                        cout << std::hex << (int)tp->PhysicalAddress[i];
                    else
                        cout << "-" << std::hex << (int)tp->PhysicalAddress[i];
                }
            cout << "\n Flags" << tp->Flags;
            cout << "\nmtu" << tp->Mtu;
            cout << "\n IfType" << tp->IfType;
            cout << "\n OperStatus" << tp->OperStatus;
            cout << "\n ipv6 ifindex :" << tp->Ipv6IfIndex;
            cout << "\nand more";
            tp = tp->Next;
        }

    }
    else {
        cout << "something went wrong";
    }
    HeapFree(GetProcessHeap(), 0, p);
    p = NULL;
    cin >> ret;
    return 0;
}

image

如您所见,没有一个地址与命令提示符中的地址匹配。

最佳答案

我发现您的代码存在一些问题:

  • 调用 GetAdaptersAddresses() 时,您没有执行足够的错误处理。

  • 您正在泄漏您分配的第一个 IP_ADAPTER_ADDRESSES 结构。

  • 您没有将 tp->Length 输出到 while (tp) 循环顶部的控制台。

  • 您没有正确检索和格式化 IP 地址!

最后一点是问题的根源。

当您尝试从列表中检索 IP 地址时,您正在错误地访问 sockaddr_X 结构。

这段代码:

sockaddr_in *si = (sockaddr_in *)&(pu->Address.lpSockaddr);

sockaddr_in6 *si = (sockaddr_in6 *)&(pu->Address.lpSockaddr);

需要像这样:

sockaddr_in *si = (sockaddr_in *)(pu->Address.lpSockaddr);

sockaddr_in6 *si = (sockaddr_in6 *)(pu->Address.lpSockaddr);

lpSockaddr 字段已经是指向 sockaddr_X 结构的指针,因此您需要对该指针值进行类型转换,请勿使用& 运算符来获取该指针本身的地址,您将转换错误的内存地址,因此您尝试为 IP 地址格式化的二进制数据是垃圾!

您还错误地调用了inet_ntop()。它需要一个指向 in_addr/in6_addr 结构体的指针作为输入,但您向其传递一个指向 sockaddr_in/sockaddr_in6< 的指针 结构代替。所以格式化的输出字符串也是垃圾!

这段代码:

inet_ntop(AF_INET, si, a, sizeof(a));

inet_ntop(AF_INET6, si, a, sizeof(a));

需要像这样:

inet_ntop(AF_INET, &(si->sin_addr), a, sizeof(a));

inet_ntop(AF_INET6, &(si->sin6_addr), a, sizeof(a));

对于链接列表中的所有任播、单播、多播、DNS 服务器和网关 IP 地址,您都犯了这两个错误。

话虽如此,尝试更多类似这样的事情:

// getadaptersinfo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <WinSock2.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
#include <iostream>

#pragma comment(lib,"IPHLPAPI.lib")
#pragma comment(lib,"Ws2_32.lib")

using namespace std;

void displayAddress(const SOCKET_ADDRESS &Address)
{
    cout << "\n  Length of sockaddr: " << Address.iSockaddrLength;
    if (Address.lpSockaddr->sa_family == AF_INET)
    {
        sockaddr_in *si = (sockaddr_in *)(Address.lpSockaddr);
        char a[INET_ADDRSTRLEN] = {};
        if (inet_ntop(AF_INET, &(si->sin_addr), a, sizeof(a)))
            cout << "\n   IPv4 address: " << a;
    }
    else if (Address.lpSockaddr->sa_family == AF_INET6)
    {
        sockaddr_in6 *si = (sockaddr_in6 *)(Address.lpSockaddr);
        char a[INET6_ADDRSTRLEN] = {};
        if (inet_ntop(AF_INET6, &(si->sin6_addr), a, sizeof(a)))
            cout << "\n   IPv6 address: " << a;
    }
}

int main()
{
    cout << "\nUsing GetAdaptersAddresses";

    ULONG size = 1024 * 15;    
    PIP_ADAPTER_ADDRESSES p = (IP_ADAPTER_ADDRESSES*) HeapAlloc(GetProcessHeap(), 0, size);
    if (!p)
    {
        cout << "\nCannot allocate memory";
        cin.get();
        return -1;
    }

    ULONG ret;
    do
    {
        ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, p, &size);
        if (ret != ERROR_BUFFER_OVERFLOW)
            break;

        PIP_ADAPTER_ADDRESSES newp = (IP_ADAPTER_ADDRESSES*) HeapReAlloc(GetProcessHeap(), 0, p, size);
        if (!newp)
        {
            cout << "\nCannot reallocate memory";
            HeapFree(GetProcessHeap(), 0, p);
            cin.get();
            return -1;
        }

        p = newp;
    }
    while (true);

    if (ret != NO_ERROR)
    {
        cout << "\nSomething went wrong. Error: " << ret;
        HeapFree(GetProcessHeap(), 0, p);
        cin.get();
        return -1;
    }

    int i = 0;
    for(PIP_ADAPTER_ADDRESSES tp = p; tp != NULL; tp = tp->Next)
    {
        ++i;
        cout << "\nLength of IP Adapter info: " << tp->Length;
        cout << "\n IPv4 IfIndex: " << tp->IfIndex;
        cout << "\n Adapter name: " << tp->AdapterName;
        cout << "\n Unicast addresses:";
        int j = 0;
        for (PIP_ADAPTER_UNICAST_ADDRESS pu = tp->FirstUnicastAddress; pu != NULL; pu = pu->Next)
        {
            ++j;
            displayAddress(pu->Address);
        }
        cout << "\n # of Unicast addresses: " << j;
        cout << "\n Anycast addresses:"; 
        j = 0;
        for (PIP_ADAPTER_ANYCAST_ADDRESS pa = tp->FirstAnycastAddress; pa != NULL; pa = pa->Next)
        {
            ++j;
            displayAddress(pa->Address);
        }
        cout << "\n # of Anycast addresses: " << j;
        cout << "\n Multicast addresses:";
        j = 0;
        for (PIP_ADAPTER_MULTICAST_ADDRESS pm = tp->FirstMulticastAddress; pm != NULL; pm = pm->Next)
        {
            ++j;
            displayAddress(pm->Address);
        }
        cout << "\n # of Multicast addresses: " << j;
        cout << "\n DNS server addresses:";
        j = 0;
        for (PIP_ADAPTER_DNS_SERVER_ADDRESS pd tp->FirstDnsServerAddress; pd != NULL; pd = pd->Next)
        {
            ++j;
            displayAddress(pd->Address);
        }
        cout << "\n # of DNS server addresses: " << j;
        cout << "\n Gateway addresses:"; 
        j = 0;
        for (PIP_ADAPTER_GATEWAY_ADDRESS_LH pg = tp->FirstGatewayAddress; pg != NULL; pg = pg->Next)
        {
            ++j;
            displayAddress(pg->Address);
        }
        cout << "\n # of Gateway addresses: " << j;
        cout << "\n DNS suffix" << tp->DnsSuffix;
        cout << "\n Description" << tp->Description;
        cout << "\n Friendly name" << tp->FriendlyName;
        if (tp->PhysicalAddressLength != 0)
        {
            cout << "\n Physical address: ";
            cout << std::hex << (int)tp->PhysicalAddress[0];
            for (UINT i = 1; i < tp->PhysicalAddressLength; i++)
                cout << "-" << std::hex << (int)tp->PhysicalAddress[i];
        }
        cout << "\n Flags" << tp->Flags;
        cout << "\n MTU" << tp->Mtu;
        cout << "\n IfType" << tp->IfType;
        cout << "\n OperStatus" << tp->OperStatus;
        cout << "\n IPv6 IfIndex :" << tp->Ipv6IfIndex;
        cout << "\n and more...";
    }
    cout << "\n# of IP Adapters: " << i;

    HeapFree(GetProcessHeap(), 0, p);

    cin.get();
    return 0;
}

关于c++ - GetAdaptersAddresses() 未给出正确的 IP 地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49735517/

相关文章:

c - 金额计算失败

c# - godot 上 GetComponent 的类似替代方案

Java 套接字客户端-服务器应用程序

c# - 在两台计算机之间进行 .NET 远程处理时出现套接字错误

c++ - 复制到 d3dtexture 的 FreeType2 字符显示为双字母

c++ - 停止计算运算符<<

c++ - 广度优先搜索题 C++

c - 指针数组分配

c - 我如何将确定数量的字符与另一个字符串连接起来?

c++ - 使用 boost spirit qi 解析器迭代填充 BGL 图