【问题标题】:Finding Local IP via Socket Creation / getsockname通过 Socket Creation / getsockname 查找本地 IP
【发布时间】:2025-12-22 09:30:16
【问题描述】:

我需要在 C++ 中获取系统的 IP 地址。我按照此处另一条评论的逻辑和建议创建了一个套接字,然后使用getsockname确定套接字绑定到的IP地址。

但是,这似乎不起作用(下面的代码)。当我应该收到 128.etc 时,我收到了无效的 IP 地址 (58.etc)

有什么想法吗?

   string Routes::systemIP(){

    // basic setup
    int sockfd;
    char str[INET_ADDRSTRLEN];
    sockaddr* sa;
    socklen_t* sl;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;

    if ((rv = getaddrinfo("4.2.2.1", "80", &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return "1";
    }

    // loop through all the results and make a socket
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("talker: socket");
            continue;
        }

        break;
    }

    if (p == NULL) {
        fprintf(stderr, "talker: failed to bind socket\n");
        return "2";
    }

    // get information on the local IP from the socket we created
    getsockname(sockfd, sa, sl);

    // convert the sockaddr to a sockaddr_in via casting
    struct sockaddr_in *sa_ipv4 = (struct sockaddr_in *)sa;

    // get the IP from the sockaddr_in and print it
    inet_ntop(AF_INET, &(sa_ipv4->sin_addr.s_addr), str, INET_ADDRSTRLEN);
    printf("%s\n", str);

    // return the IP
    return str;
}

【问题讨论】:

    标签: c++ sockets ip-address ip


    【解决方案1】:

    您不需要分配套接字来获取机器的可用 IP 地址。您可以改用套接字 API gethostname() 和 gethostbyname() 函数。或者,在 Windows 上,您也可以使用 Win32 API GetAdaptersInfo() 或 GetAdaptersAddresses() 函数。

    【讨论】:

    • 这会给我所有机器的IP地址,对吗?我需要知道我选择的 IP 地址是与选择的远程系统(在本例中为 4.2.2.1)进行通信的 IP。有什么方法可以轻松过滤所有 IP 地址?
    • 那你必须连接目标机器,连接后在socket上调用getsockname
    • 连接是最准确的。但是,如果您不想浪费连接,Win32 API 具有 GetBestInterface/Ex() 函数(但它们仅适用于 IPv4)。
    • 有 linux 等效的 GetBestInterface 吗?
    • 我不是 Linux 开发人员,所以我不知道,对不起。
    【解决方案2】:

    您的代码已包含提示:failed to bind socket。但是您剪切了尝试连接的代码部分(您是从 Stevens UnP 复制的吗?)。套接字没有连接到任何东西,所以网络堆栈还没有给它分配本地地址。

    一旦你连接了套接字,内核必须根据路由表为其选择本地地址。此时getsockname(2) 将按预期工作。

    【讨论】:

    • 这里不需要连接——这是一个UDP数据报连接结构的启动。我曾假设套接字的创建会分配一个本地地址,显然不是?
    • connect(2) 也适用于 UDP 套接字。它实际上非常整洁。如果您有 UnP 书籍 - 请阅读有关已连接 UDP 套接字的信息。要回答您的问题 - 不,创建套接字只是保留一个文件描述符,它不会将其绑定到任何地址。
    • 我实际上是在看 Beej 的套接字结构网络编程指南。
    • 这也是一个很好的来源,但无论如何都要获得最新版本的 UnP(现在是第 3 版)——这是一项非常好的投资,您会一直使用它。我知道我知道。