2017-05-21 11 views
0

私は以下のようなコードを書いています。このコードは、PASSIVE_SOCKET(サーバーがソケットにバインドされている場所)とCONNECTION_SOCKET(クライアントが接続されている場所)の両方でIPアドレスを取得できるようにする必要があります。Cソケットプログラミング:IPアドレス(IPv6またはIPv4)サーバーの境界を取得し、クライアントを接続しますか?

result_t print_socket_address(int sockfd, socket_type_t socket_type) { 

    char *ip_address; // address (passive) socket was binded to 
    int port; // port (passive) socket was binded to 

    switch(socket_type) 
    { 
     case PASSIVE_SOCKET: 
      if(get_current_address_and_port(sockfd, &ip_address, &port) == FAILURE) { 
       fprintf(stderr, "get_current_address_and_port: faild!\n"); 
       free(ip_address); 
       return FAILURE; 
      } 
      printf("Created passive socket %d binded to %s:%d\n", sockfd, ip_address, port); 
      break; 
     case CONNECTION_SOCKET: 
      if(get_peer_address_and_port(sockfd, &ip_address, &port) == FAILURE) { 
       fprintf(stderr, "get_peer_address_and_port: faild!\n"); 
       free(ip_address); 
       return FAILURE; 
      } 
      printf("Socket %d connected to %s:%d\n", sockfd, ip_address, port); 
      break; 
     default: 
      fprintf(stderr, "Incorrect socket type!\n"); 
      free(ip_address); 
      return FAILURE; 
    } 

    free(ip_address); 
    return SUCCESS; 
} 

/** 
* function retrieves current ip address and port 
* socket is bound to for given socket file descriptor 
*/ 
result_t get_current_address_and_port(int sockfd, char **ip_address, int *port) { 

    struct sockaddr sockaddr; 
    socklen_t sockaddrlen = sizeof(sockaddr); 

    if(getsockname(sockfd, &sockaddr, &sockaddrlen) < 0) { 
     fprintf(stderr, "getsockname: %s\n", strerror(errno)); 
     return FAILURE; 
    } 

    sockaddr.sa_family = AF_INET6; 

    return get_address_and_port_from_sockaddr(&sockaddr, ip_address, port); 
} 

/** 
* function retrieves peer ip address and port 
* socket is connected to for given socket file descriptor 
*/ 
result_t get_peer_address_and_port(int sockfd, char **ip_address, int *port) { 

    struct sockaddr sockaddr; 
    socklen_t sockaddrlen = sizeof(sockaddr); 

    if(getpeername(sockfd, &sockaddr, &sockaddrlen) < 0) { 
     fprintf(stderr, "getpeername: %s\n", strerror(errno)); 
     return FAILURE; 
    } 

    return get_address_and_port_from_sockaddr(&sockaddr, ip_address, port); 
} 

/** 
* function unwrap ip address and port from addrinfo structure 
*/ 
result_t get_address_and_port_from_addrinfo(const struct addrinfo *addrinfo, char **ip_address, int *port) { 

    return get_address_and_port_from_sockaddr((struct sockaddr *)addrinfo->ai_addr, ip_address, port); 
} 

/** 
* function unwrap ip address and port from sockaddr structure 
*/ 
result_t get_address_and_port_from_sockaddr(const struct sockaddr *sockaddr, char **ip_address, int *port) { 

    *ip_address = (char *) malloc(INET6_ADDRSTRLEN * sizeof(char)); 

    // converting network address to presentation address 
    if(inet_ntop(sockaddr->sa_family, get_in_addr(sockaddr), *ip_address, INET6_ADDRSTRLEN * sizeof(char)) == NULL) { 
     fprintf(stderr, "inet_ntop: %s\n", strerror(errno)); 
     return FAILURE; 
    } 

    // converting network port to host port 
    *port = ntohs(get_in_port(sockaddr)); 

    return SUCCESS; 
} 

/** 
* function unwrap in_addr or in6_addr structure from 
* sockaddr structure depending on address family 
* AF_INET or AF_INET6 
*/ 
void *get_in_addr(const struct sockaddr *sa) { 

    if(sa->sa_family == AF_INET) // IPv4 address 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    // else IPv6 address 
    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

/** 
* function unwrap in_port from sockaddr structure 
* depending on address family AF_INET or AF_INET6 
*/ 
in_port_t get_in_port(const struct sockaddr *sa) 
{ 
    if(sa->sa_family == AF_INET) // IPv4 address 
     return (((struct sockaddr_in*)sa)->sin_port); 
    // else IPv6 address 
    return (((struct sockaddr_in6*)sa)->sin6_port); 
} 

しかし、このコードを使用すると、私は奇妙な動作をします。 431C:F9:へ:: ba54バインドさパッシブソケット4に作成

:55401

55401はポート番号で、それは正しいです私のサーバーの境界ソケットは、例えば、あるIPアドレスが返されます。しかし、これは何ですか:: ba54:431c:f9?おそらく、これはIPv6だと思います。しかし、なぜ?ローカルエリアネットワークのマイコンピュータにIPアドレス192.168.8.102があります! クライアントプログラムでこのサーバーに接続しようとすると、192.168.8.102のIPアドレスを使用しなければなりません。ba54:431c:f9「ルートが見つかりません」というエラーが表示されますか?クライアントがサーバと192.168.8.102のIPアドレスを使用して接続し、接続したコンピュータのIPアドレスとポート番号を出力すると、次のような別のODD IPアドレスが得られます。

ソケット3 :: 3300 :5208:6d16:9c88:55401

ここでポート番号が一致し、IPアドレスが正しくありません。 クライアントソケットは、サーバと接続する前にローカルにバインドしている間に、接続しているコンピュータのIPアドレスと同じIPアドレスにバインドされています(実際にはLANネットワーク内のコンピュータとは物理的に異なります):: 3300:5208:6d16:9c88: 52040ここで、52040はクライアントがソケットをバインドしたポートです。

私は、サーバコンピュータ192.168.8.1のIPアドレスをIPv6に変換しようとしましたが、クライアントで使用された場合、0:0:0:0:0:ffff:c0a8:866のようなものがあります。サーバーに接続するプログラムが正しく動作します! :: 3300:5208:6d16:9c88:しかし、上記の関数を使用してクライアントのような、この全く異なるIPアドレスを印刷52040

を、どのように私は、この関数を記述する必要があります

  1. サーバーの印刷IPアドレスを有効にし、 (一般にIPv6またはIPv4は任意のアドレス/任意のポートに接続できます)

  2. クライアントは、バインドされているIPアドレスとポート番号を印刷して接続できます必要に応じてIPv4またはIPv6を使用します)。

クライアントプログラムで使用できるサーバープログラムのIPアドレスとポート番号に両方を接続したいと考えています。ネットワークの設定で見つかったコンピュータのアドレスで、ポート番号が正しいと仮定して接続しようとする必要があります。

+0

あなたは、このコードを達成しようとしているもの: 'sockaddr.sa_family = AF_INET6;'?あなたはあなたがあなたが戻って予期せぬIPv6アドレスを説明するかもしれないIPv6に得たアドレスの家族を変更するように私のように見えます。 –

答えて

1

この行をget_current_address_and_portから削除します。

sockaddr.sa_family = AF_INET6; 

私はそのラインがあなたのコードの中に書かれてしまったのか分からないが、それは正しくないです。

この行を削除すると、IPv4の問題のほとんどが解決されます。

コードにはstruct sockaddrを使用するように固定配線されています。 IIRCでは、sockaddrはIPv6アドレスには十分ではありません。 getsocknamegetpeernameへの最初の呼び出しのためにsockaddr_storageに変換することをお勧めします。そうすれば、コードはIPv4とIPv6の両方でよりうまく動作します。

例フィックスアップ:

result_t get_current_address_and_port(int sockfd, char **ip_address, int *port) { 

    struct sockaddr_storage address = {0}; 
    socklen_t sockaddrlen = sizeof(address); 

    if(getsockname(sockfd, (struct sockaddr*)(&address), &sockaddrlen) < 0) { 
     fprintf(stderr, "getsockname: %s\n", strerror(errno)); 
     return FAILURE; 
    } 

    return get_address_and_port_from_sockaddr((struct sockaddr*)(&address), ip_address, port); 
} 


result_t get_peer_address_and_port(int sockfd, char **ip_address, int *port) { 
    struct sockaddr_storage address = {0}; 
    socklen_t sockaddrlen = sizeof(address); 

    if(getpeername(sockfd, (struct sockaddr*)(&address), &sockaddrlen) < 0) { 
     fprintf(stderr, "getpeername: %s\n", strerror(errno)); 
     return FAILURE; 
    } 

    return get_address_and_port_from_sockaddr((struct sockaddr*)(&address), ip_address, port); 
} 
+0

この行 'sockaddr.sa_family = AF_INET6;'はテストのためだけに追加されたもので、私はこの問題をstackoverflowに投稿する前に削除することを忘れないでください。 –

+0

今、私はそのようなメッセージを得ています: "作成されたパッシブソケット4バインド::: 55494" –

+0

これは正しいIPv6です。ローカルソケットはINADDR_ANY(0)にバインドされています。これは「すべてのアダプタで待機中」を意味します。文字列として、これはIPv6アドレスとして '::'に変換されます。あなたはあなたのソケットがどのように作成またはバインドされているかを示していませんでしたが、IPv6ソケットを作成したか、コードパスにハードコードされた 'AF_INET6'フラグを保持していると思われます。 – selbie

関連する問題