getaddrinfo 未获取 ipv6 地址

发布于 2024-12-25 12:33:20 字数 6719 浏览 4 评论 0原文

我正在尝试获取 ipv4 和 ipv6 地址并使用它们连接到服务器,但我只能使用 ipv4 地址连接。它实际上是一个标准代码。 当我运行服务器和客户端时, ipv4 和 ipv6 地址都在 /etc/hosts 中,

192.155.112.18 hostname.site hostname
fe80::a00:28ff:fe23:47a0 hostname.site hostname

输出是 服务器:

usage: showip hostname
server: waiting for connections...
server: got connection from 192.155.112.18

客户端:

client: connecting to 192.155.112.18
client: connecting to 192.155.112.18
client: received 'Hello, world!'

getaddrinfo 也获取 ipv6 地址,但没有我需要获取的接口 fe80::a00:28ff:fe23:47a0%eth0 之类的。我怎样才能制作一个标准代码获取ipv4和ipv6(带接口)

#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <ifaddrs.h>

#define PORT "3490"  // the port users will be connecting to

void error(const char *msg)
{
    perror(msg);
    exit(1);
}
int gHostIP;
#define BACKLOG 10     // how many pending connections queue will hold

void sigchld_handler(int s)
{
   while(waitpid(-1, NULL, WNOHANG) > 0);
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
  if (sa->sa_family == AF_INET) 
  {
    return &(((struct sockaddr_in*)sa)->sin_addr);
   }

   return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main()
{
   int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
   struct addrinfo hints, *servinfo, *p;
   struct sockaddr_storage their_addr; // connector's address information
   socklen_t sin_size;
   struct sigaction sa;
   int yes=1;
   char s[INET6_ADDRSTRLEN];
   int rv;
       char *arg;

       arg = (char*)malloc(20*sizeof(char));

       fprintf(stderr,"usage: showip hostname\n");

       memset(&hints, 0, sizeof(hints));
       hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
       hints.ai_socktype = SOCK_STREAM;


       if ((rv = getaddrinfo("myhostname", PORT, &hints, &servinfo)) != 0) {
         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
         return 1;
       }
       for(p = servinfo; p != NULL; p = p->ai_next) {
          if ((sockfd = socket(p->ai_family, p->ai_socktype,
                  p->ai_protocol)) == -1) {
              perror("server: socket");
            continue;
          }

          if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                  sizeof(int)) == -1) {
              perror("setsockopt");
              exit(1);
          }
           /*if(p->ai_family == AF_INET6)
              strcat(p->ai_addr,"%eth3");*/
           if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
              close(sockfd);
              perror("server: bind");
              continue;
            }

          break;
       }

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

     freeaddrinfo(servinfo); // all done with this structure

     if (listen(sockfd, BACKLOG) == -1) {
    perror("listen");
    exit(1);
     }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
      perror("sigaction");
      exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1)
    {  // main accept() loop
      sin_size = sizeof their_addr;
      new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
      if (new_fd == -1) {
          perror("accept");
          continue;
      }

      inet_ntop(their_addr.ss_family,
          get_in_addr((struct sockaddr *)&their_addr),
          s, sizeof s);
      printf("server: got connection from %s\n", s);

      if (!fork()) { // this is the child process
          close(sockfd); // child doesn't need the listener
          if (send(new_fd, "Hello, world!", 13, 0) == -1)
            perror("send");
          close(new_fd);
          exit(0);
      }
      close(new_fd);  // parent doesn't need this
     }

     return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/resource.h>
#include <sched.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <ifaddrs.h>

#define PORT "3490" // the port client will be connecting to

#define MAXDATASIZE 100 // max number of bytes we can get at once
int gHostIP;

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}



int main(int argc, char *argv[])
{
    int sockfd, numbytes;
    char buf[MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];
    char *arg;
    arg = (char*)malloc(20*sizeof(char));

    struct ifaddrs *ifaddr, *ifa;
    int family, s1;
    char host[NI_MAXHOST];


    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;


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


    for (p = servinfo; p != NULL; p = p->ai_next)
    {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("client: socket");
        continue;
        } 
        inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
               s, sizeof s);
         printf("\nclient: connecting to %s\n", s);
         if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("\nclient: connect");
        continue;
         }

         break;
    }

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

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
        s, sizeof s);
    printf("client: connecting to %s\n", s);

    freeaddrinfo(servinfo);

    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
            perror("recv");
            exit(1);
    }

    buf[numbytes] = '\0';

    printf("client: received '%s'\n",buf);

    close(sockfd);

    return 0;
}

I am trying to get both ipv4 and ipv6 adresses and connect to server with them but i can only connect with ipv4 address. It is a standard code actually.
both ipv4 and ipv6 addresses are in /etc/hosts

192.155.112.18 hostname.site hostname
fe80::a00:28ff:fe23:47a0 hostname.site hostname

when i run both server and client the outputs are
server:

usage: showip hostname
server: waiting for connections...
server: got connection from 192.155.112.18

client:

client: connecting to 192.155.112.18
client: connecting to 192.155.112.18
client: received 'Hello, world!'

getaddrinfo gets ipv6 address too but without interface i neeed to get
fe80::a00:28ff:fe23:47a0%eth0 sth like that. How can i make a standard code get ipv4 and ipv6(with interface)

#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <ifaddrs.h>

#define PORT "3490"  // the port users will be connecting to

void error(const char *msg)
{
    perror(msg);
    exit(1);
}
int gHostIP;
#define BACKLOG 10     // how many pending connections queue will hold

void sigchld_handler(int s)
{
   while(waitpid(-1, NULL, WNOHANG) > 0);
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
  if (sa->sa_family == AF_INET) 
  {
    return &(((struct sockaddr_in*)sa)->sin_addr);
   }

   return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main()
{
   int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
   struct addrinfo hints, *servinfo, *p;
   struct sockaddr_storage their_addr; // connector's address information
   socklen_t sin_size;
   struct sigaction sa;
   int yes=1;
   char s[INET6_ADDRSTRLEN];
   int rv;
       char *arg;

       arg = (char*)malloc(20*sizeof(char));

       fprintf(stderr,"usage: showip hostname\n");

       memset(&hints, 0, sizeof(hints));
       hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
       hints.ai_socktype = SOCK_STREAM;


       if ((rv = getaddrinfo("myhostname", PORT, &hints, &servinfo)) != 0) {
         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
         return 1;
       }
       for(p = servinfo; p != NULL; p = p->ai_next) {
          if ((sockfd = socket(p->ai_family, p->ai_socktype,
                  p->ai_protocol)) == -1) {
              perror("server: socket");
            continue;
          }

          if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                  sizeof(int)) == -1) {
              perror("setsockopt");
              exit(1);
          }
           /*if(p->ai_family == AF_INET6)
              strcat(p->ai_addr,"%eth3");*/
           if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
              close(sockfd);
              perror("server: bind");
              continue;
            }

          break;
       }

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

     freeaddrinfo(servinfo); // all done with this structure

     if (listen(sockfd, BACKLOG) == -1) {
    perror("listen");
    exit(1);
     }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
      perror("sigaction");
      exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1)
    {  // main accept() loop
      sin_size = sizeof their_addr;
      new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
      if (new_fd == -1) {
          perror("accept");
          continue;
      }

      inet_ntop(their_addr.ss_family,
          get_in_addr((struct sockaddr *)&their_addr),
          s, sizeof s);
      printf("server: got connection from %s\n", s);

      if (!fork()) { // this is the child process
          close(sockfd); // child doesn't need the listener
          if (send(new_fd, "Hello, world!", 13, 0) == -1)
            perror("send");
          close(new_fd);
          exit(0);
      }
      close(new_fd);  // parent doesn't need this
     }

     return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/resource.h>
#include <sched.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <ifaddrs.h>

#define PORT "3490" // the port client will be connecting to

#define MAXDATASIZE 100 // max number of bytes we can get at once
int gHostIP;

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}



int main(int argc, char *argv[])
{
    int sockfd, numbytes;
    char buf[MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p;
    int rv;
    char s[INET6_ADDRSTRLEN];
    char *arg;
    arg = (char*)malloc(20*sizeof(char));

    struct ifaddrs *ifaddr, *ifa;
    int family, s1;
    char host[NI_MAXHOST];


    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;


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


    for (p = servinfo; p != NULL; p = p->ai_next)
    {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("client: socket");
        continue;
        } 
        inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
               s, sizeof s);
         printf("\nclient: connecting to %s\n", s);
         if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("\nclient: connect");
        continue;
         }

         break;
    }

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

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
        s, sizeof s);
    printf("client: connecting to %s\n", s);

    freeaddrinfo(servinfo);

    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
            perror("recv");
            exit(1);
    }

    buf[numbytes] = '\0';

    printf("client: received '%s'\n",buf);

    close(sockfd);

    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁月流歌 2025-01-01 12:33:20

您正在使用链接本地地址作为您的 ipv6 地址,最好使用像 2001:db8:1::1/64 这样的全球单播地址,而不是

以下命令作为 root 添加它:

ip -6 addr add 2001:db8:1::1/64 dev eth0

使用 客户:

ip -6 addr add 2001:db8:1::2/64 dev eth0

You are using a link local address as your ipv6 address, its better to use a global unicast address like 2001:db8:1::1/64 instead

as root add it using this command:

ip -6 addr add 2001:db8:1::1/64 dev eth0

and on the client:

ip -6 addr add 2001:db8:1::2/64 dev eth0
薄荷港 2025-01-01 12:33:20

如果您的服务器绑定在 ipv4 地址上,那么您只能接受 ipv4 客户端。

问题是你的 getaddrinfo() 首先返回 ipv4 。 (有人工作得很好,因为他们的 getaddrinfo() 首先返回 ipv6)

所以你可以将代码更改为

for (p = res; p!= NULL; p = p->ai_next) {
    if (p->ai_family == AF_INET6 && (sock = socket(p->ai_family, p-
        ai_socktype, p->ai_protocol)) < 0
    ) {}
}

If your server bind on a ipv4 address, then you can only accept ipv4 client.

The problem is your getaddrinfo() return ipv4 first. (somebody works fine because their getaddrinfo() return ipv6 first)

so you can change code to

for (p = res; p!= NULL; p = p->ai_next) {
    if (p->ai_family == AF_INET6 && (sock = socket(p->ai_family, p-
        ai_socktype, p->ai_protocol)) < 0
    ) {}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文