2012-01-05 10 views
2

私はipv4とipv6の両方のアドレスを取得しようとしており、それらのサーバに接続しようとしていますが、私はipv4アドレスのみで接続できます。それは実際には標準的なコードです。getaddrinfoはipv6アドレスを取得しません

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取得 IPv4とIPv6の両方のアドレスは、/ etc/hostsの

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

私は、サーバーとクライアントの両方を実行したときに出力が サーバー表示していますipv6アドレスもあまりにもインターフェイスなしで私は fe80 :: a00:28ff:fe23:47a0%eth0 sthのように取得します。どのように私は、標準的なコードを作ることができます(インターフェイスで)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

にコードを変更することができます(誰かがIPv6の最初を返す彼らはgetaddrinfo()ので、正常に動作します)と、それリンクローカルアドレスで私のためにうまくいきました。私はそれが答えではないことを知っていますが、あなたの問題を解決するのに役立つことを願っています... – Gerd

+0

スコープIDは返された 'ai_addr'構造体の' sin6_scope_id'フィールドにあります。 –

答えて

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

0

のIPv4アドレス上のサーバーバインドした場合は、IPv4のみのクライアントを受け入れることができます。

問題は、getaddrinfo()が最初にipv4を返すことです。私はちょうど(IPv6が有効になって)自己書かれたTCPサーバとクライアントコードを試してみた

ので、あなたが

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 
    ) {} 
} 
関連する問題