2016-04-24 15 views
3

現在、次のプログラムはIPv4アドレスを使用してのみ接続します。 サーバーのIPv6アドレスまたはIPv4アドレスのいずれかを使用してサーバー(IPv4とIPv6クライアントを受け入れることの互換性)に接続するように変更します。クライアントプログラムをIPv4またはIPv6経由で接続したい

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

      #include "common.h" 
      #include "client.h" 



      int 
      CreateClientTCP(const char *svrHost, 
          unsigned short svrPort, 
          char *svrName, 
          int svrNameLen) 
      { 
       int sock; 
       struct sockaddr_in svrAddr; 

       sock = socket(AF_INET, SOCK_STREAM, 0); 
       if (sock < 0) { 
        perror("Failed to allocate the client socket"); 
        exit(EXIT_FAILURE); 
       } 

       memset(&svrAddr, 0, sizeof(svrAddr)); 
       svrAddr.sin_family = AF_INET; 
       svrAddr.sin_port = htons(svrPort); 

       if (inet_pton(AF_INET, svrHost, &svrAddr.sin_addr.s_addr) <= 0) { 
        perror("Failed to convert IP address\n"); 
        exit(EXIT_FAILURE); 
       } 

       SocketAddrToString(&svrAddr, svrName, svrNameLen); 
       Log("Attempting %s\n", svrName); 

       if (connect(sock, (struct sockaddr *)&svrAddr, sizeof(svrAddr)) < 0) { 
        perror("Failed to connect to the server"); 
        exit(EXIT_FAILURE); 
       } 

       return sock; 
      } 



      int 
      main(int argc, char *argv[]) 
      { 
       int sock; 
       ClientArgs cliArgs; 
       char svrName[INET_ADDRSTRLEN + PORT_STRLEN]; 

       ParseArgs(argc, argv, &cliArgs); 

       sock = CreateClientTCP(cliArgs.svrHost, cliArgs.svrPort, 
             svrName, sizeof svrName); 

       Log("Connected to server at %s\n", svrName); 

       Client(sock, &cliArgs); 

       close(sock); 
       Log("\nDisconnected from server at %s\n", svrName); 
       return 0; 
      } 

答えて

1

あなたはIPv6とIPv4の両方をサポートする機能を使用する必要があります、たとえば、inet_ptonを使用していない、代わりにgetaddrinfoを使用し、それは両方のプロトコルバージョンのアドレスを解析し、使用するためにあなたの右の家族に伝えることができます。

以降のネットワークコールでは、にハードコードするのではなく、getaddrinfoで返されたファミリを使用する必要があります。 sock = socket(addr->ai_family, ...)

また、このIPV6のイントロを読んで、とても良いスタートです。

私はあなたが開始するためにこれらの3ヶ所を変更する必要があると思うあなたのコードの特定の変化については、

https://www.akkadia.org/drepper/userapi-ipv6.html

// struct sockaddr_in svrAddr; <-- sockaddr_in is for ipv4 address 
struct sockaddr_storage svrAddr; 

// inet_pton(AF_INET, svrHost, &svrAddr.sin_addr.s_addr) <-- IPV4 only 
struct addrinfo *res; 
getaddrinfo(svrHost, NULL, &hint, &res); 

// sock = socket(AF_INET, SOCK_STREAM, 0); <-- IPV4 only 
sock = socket(result->ai_family, SOCK_STREAM, 0); 
+0

プログラム内で必要となる変更は何ですか? 別のクライアントをコーディングする必要がありますか? – ramnarayanan

+0

@ramnarayananいいえ、両方のバージョンをサポートするために1つのクライアントを使用することを目的としています。 – fluter

+0

私は共有したいエラーの流れがあります。 @fluter – ramnarayanan

2

fluterの答えに加えて、あなたのコードAの構造を変更する必要がありますビット。

ソケットを作成してからアドレスを検索する代わりに、getaddrinfoを呼び出して、指定したホスト名のすべてのアドレスを取得する必要があります。ホスト名はデュアルスタックなので、複数のIPv4アドレスやIPv6アドレスを返すことがあります。彼らは通常、あなたがそれらを試すべき順序でソートされます。接続が成功するまで、すべてのアドレスを1つずつループします。

一部のアドレスはIPv4になり、一部はIPv6になるため、ソケットを前面に作成することはできません。それぞれのアドレスに対して、接続しようとしているアドレスのアドレスファミリに属する​​新しいソケットを作成してください。 Fluterはすでにあなたに方法を示しました。

接続が成功すると、ループを解除して確立された接続を使用します。

+1

いくつかのプラットフォームでは、両方のプロトコルで通信するためにIPv6ソケットを使用できます。しかし、私はそのようにしてコードを移植することはできないと確信していません。しかし、アドレスごとに別々のソケットを作成することには、複数の並行して試行できるようになるという利点があります。 – kasperd

関連する問題