为什么我无法将listenfd与我的公共IPv4地址绑定,但我可以用我的公共IPv6地址绑定?

问题描述 投票:0回答:1

这是我的案例:

我从 https://whatismyipaddress.com/ 获取了我的公共 IPv6 和公共 IPv4,就像:

IPv6:2603:6080:1001:100:2042:----:----

IPv4:75.177.130.***。

然后我使用下面的代码作为TCP/IP服务器程序:

我可以将listendfd与IPv6地址绑定,并且可以从运行TCP/IP客户端程序的同一台或另一台计算机与其建立连接(设置hints.ai_family = AF_INET6),

但我无法将listendfd与IPv4地址绑定,也无法连接到它(设置hints.ai_family = AF_INET)。

#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/un.h>

#define LISTENQ 10
#define MAXLINE 8000

int open_listenfd(char *port)
{
    struct addrinfo hints, *listp, *p;
    int s, listenfd, optval=1;
    char ipstr[INET6_ADDRSTRLEN+1];
    
    // Get a list of potential server addresses
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; 
    hints.ai_flags |= AI_NUMERICSERV;
    hints.ai_family = AF_INET;

    s = getaddrinfo("75.177.130.***", port, &hints, &listp);
    if (s != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
        exit(EXIT_FAILURE);
    }

    // Walk the list for one that we can bind to
    for(p = listp; p; p = p->ai_next) {

        switch(p->ai_family) {
            case AF_INET: {
                struct sockaddr_in *addr_in = (struct sockaddr_in *)p->ai_addr;
                printf("bind: family=AF_INET addr=%s port=%u\n",
                   inet_ntoa(addr_in->sin_addr),
                   ntohs(addr_in->sin_port));
                break; 
            }
            case AF_INET6: {
                struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) p->ai_addr;
                printf("bind: family=AF_INET6 IP address: %s\n", inet_ntop(AF_INET6, &(addr_in6->sin6_addr), ipstr, INET6_ADDRSTRLEN));
                printf("Port: %i\n", ntohs(addr_in6->sin6_port)); 
                break;
            }
        }

        // Create a socket descriptor
        if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))<0)
            continue;
    
        // Eliminates "Address already in use"l error from bind
        setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int));

        // Bind the descriptor to the address
        // NULL coundn't bind port 8080, which might have been used by other services 
        if(bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)
            break;

        fprintf(stderr, "bind error: %s\n", gai_strerror(s));
        close(listenfd); // Bind failed, try the next
    }
    // Clean up
    freeaddrinfo(listp);
    if(!p) // No address worked
        return -1;

    // Make it a listening socket ready to accept connectionn request
    if(listen(listenfd, LISTENQ) < 0) {
        close(listenfd);
        return -1;
    }
    return listenfd;
}

int main() {
    int lisfd, connfd;
    socklen_t clientlen;
    struct sockaddr_storage clientaddr;
    char client_hostname[MAXLINE], client_port[MAXLINE];

    char *listenport = "8798";
    lisfd = open_listenfd(listenport);
    printf("listenfd: %i\n", lisfd);

    while(1) {
        clientlen = sizeof(clientaddr);
        connfd = accept(lisfd, (struct sockaddr *)&clientaddr, &clientlen);
        if (connfd != -1) {
            getnameinfo((struct sockaddr *)&clientaddr, clientlen, client_hostname, MAXLINE, client_port, MAXLINE, 0);
            printf("accepted connection from(%s %s)\n", client_hostname, client_port);
            close(connfd);
        }
    }
}

顺便说一句,我可以使用我的计算机的私有 IPv4 地址 192.168.0.1* 进行绑定,并让我的 TCP/IP 客户端程序运行我家中另一台具有私有 IPv4 地址 192.168.0.5* 的计算机来与其连接。

但是,如果我的一台计算机使用 iPhone 的连接,该计算机会生成不同的私有 IPv4 地址,例如 172.20.**.*,并且我无法从家里运行 TCP/IP 客户端的另一台计算机与其建立连接程序。

谁能给我解释一下这是为什么吗?欢迎任何评论!谢谢!

c sockets binding ipv6 ipv4
1个回答
0
投票

最大的区别是 IPv4 通常使用 NAT,而 IPv6 则不使用。这意味着您的 IPv6 地址实际上属于您的 PC/手机/平板电脑等(每个人都获得数十亿个 IPv6 地址,因此每台设备都有自己的),而您的 IPv4 地址(您通常只获得一个)属于您的 NAT 路由器。这就是为什么你的电脑无法绑定到它。

如果您想监听 IPv6 地址:

  • 找出您的权益本地地址,使用 IPv6,您可以获得多个地址。为了保护隐私,您通常拥有一个或多个短期地址,以及一个稳定地址。你通常想听后者
  • 绑定到您的本地地址(或者只是监听所有地址,更容易!)
  • 在路由器中配置防火墙以允许传入连接

收听 IPv4:

  • 找出您的公共地址是什么
  • 找出您的内部(私人)地址是什么
  • 收听内部地址
  • 配置 NAT 路由器,将公共地址的特定端口转发到内部地址的特定端口
  • 在路由器中配置防火墙以允许传入连接

我希望这能澄清差异

© www.soinside.com 2019 - 2024. All rights reserved.