2012-01-05 46 views
2

我想获得ipv4和ipv6地址并连接到他们的服务器,但我只能与ipv4地址连接。这实际上是一个标准代码。 IPv4和IPv6地址是在/ etc /主机getaddrinfo没有得到ipv6地址

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; 
} 
+0

我只是想你的客户端代码与自写TCP服务器(支持IPv6),它用链接本地地址工作得很好。我知道这不是一个答案,但我希望它有助于解决您的问题... – Gerd 2014-04-09 13:44:32

+0

作用域ID位于返回的'ai_addr'结构的'sin6_scope_id'字段中。 – 2017-01-27 20:15:31

回答

2

您使用的链路本地地址作为IPv6地址,它能够更好地使用全局单播地址等2001:db8:1::1/64代替

作为根使用该命令添加:

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

和客户端上:

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

谢谢你的回复。 – Brknl 2012-01-09 13:55:29

0

如果在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 
    ) {} 
}