0
int print_socket_info(int sock_fd, struct sockaddr_in *sin, short protocol){
    char dbg[INET_ADDRSTRLEN];
    char *famstr;
inet_ntop(protocol, &(sin->sin_addr), dbg, INET_ADDRSTRLEN);
printf("============ SOCKET INFORMATION =============\n");
printf("!** socket: %d\n", sock_fd);
printf("!** info->ai_addr: sockaddr_in(\n");
famstr = fam2str(sin->sin_family);
printf("!**     sin_family:    %s\n", famstr);
printf("!**     sin_port:      %d\n", ntohs(sin->sin_port));
printf("!**     sin_addr:      in_addr( s_addr : '%s' )\n", dbg);
printf("!**)\n");
printf("=============================================\n");
return 1;
}

char *fam2str(int fam){
switch (fam){
    case AF_INET:
        return "AF_INET";
    case AF_INET6:
        return "AF_INET6";
    case AF_UNSPEC:
        return "AF_UNSPEC";
    default:
        return "(UNKNOWN)";
    }
    return "(UNKNOWN)";
}

次のように Hint.ai_addr を渡すと (情報を無視します->...文字列の一部です):

print_socket_info(sock, (struct sockaddr_in *)hint.ai_addr, protocol);

...次に、次の出力を取得します...

============ SOCKET INFORMATION =============
!** socket: 3
!** info->ai_addr: sockaddr_in(
!**     sin_family:    AF_INET6
!**     sin_port:      8081
!**     sin_addr:      in_addr( s_addr : '::1' )
!**)
=============================================

... 情報が正しく印刷されます。次に、関数を呼び出します。

res =  getaddrinfo(target_host, target_port, &hint, &info);

これまでのところエラーは発生しません。ここで、リンクされたリストをループします。

struct addrinfo *rp;
for (rp = info; rp != NULL; rp = rp->ai_next){
    printf("==> Another element.\n");
    print_socket_info(sock, (struct sockaddr_in *) rp->ai_addr, protocol);
}

... 要素を 1 つだけ出力します。

============ SOCKET INFORMATION =============
!** socket: 3
!** info->ai_addr: sockaddr_in(
!**     sin_family:    AF_INET6
!**     sin_port:      8081
!**     sin_addr:      in_addr( s_addr : '::' )
!**)
=============================================

もちろん、これは bind() で大混乱を引き起こしています。なぜ住所が短縮されたのですか?

その他の奇妙な点: 127.0.0.1 を渡して AF_INET4 を使用すると、アドレスはプログラム全体で維持されます (ただし、結果は 1 つしか得られず、バインドは失敗します)。

何か案は?前もって感謝します。

4

1 に答える 1

1

あなたのprint_socket_info機能は間違っています。(IPv4 ソケット アドレス構造)を取りますが、struct sockaddr_in *IPv4 と IPv6 の両方をサポートすることを意図しています。

ジェネリック(任意のタイプのソケット アドレス)print socket_infoを取るように宣言する必要があります。struct sockaddr *適切な対策として、sin引数の名前を に変更しsaて、型ではなくジェネリック型であることを示しますstruct sockaddr_in。次に、関数内でsin->sin_family、実際のファミリが何であるかを確認し、必要に応じsinて astruct sockaddr_in *またはにキャストして続行しstruct sockaddr_in6ます。

既存の関数で何が起こっているかというと、struct sockaddr_in *関数全体でそれを扱っているだけで、次の結果が得られます (少なくとも Linux では)。

  • ファミリはすべてのタイプの sockaddr の構造内で同じオフセットにあることが保証されているため、チェックsin_familyは問題ありstruct sockaddr_inません。これは、UNIX ドメイン ソケットの場合struct sockaddr_in6でも、他のすべてのあいまいなアドレス ファミリの sockaddr 構造の場合でも同様です。struct sockaddr_un
  • in はたまたま構造内で in と同じオフセットにあるためsin_port、チェックするときにそれを回避できて幸運です。sin_portstruct sockaddr_insin6_portstruct sockaddr_in6
  • sin_addrIPv4 の場合、構造体のsin_addr直後にif が機能しませんsin_portが、IPv6 の場合、その場所 (つまり、sin6_flowinfo) に他のフィールドが見つかります。sin6_addr別の場所にあります。

もう1つの問題print_socket_infoは、IPv6には短すぎる長さで宣言されているため、文字列バッファーにIPv4アドレス文字列に十分なスペースしかないことですINET_ADDRSTRLEN(IPv6の場合、必要INET6_ADDRSTRLENです。また、関数はパラメーターを取る必要はありませんprotocol。この情報すでに sockaddr に埋め込まれています。

int print_socket_info(int sock_fd, struct sockaddr *sa){
    char dbg[INET6_ADDRSTRLEN]; /* the larger of the two sizes */
    char *famstr;
    unsigned short port;

   switch (sa->sa_family):
        case AF_INET4:    
            inet_ntop(AF_INET4, &(((struct sockaddr_in *)sa)->sin_addr), dbg, sizeof(dbg));
            port = ((struct sockaddr_in *)sa)->sin_port;
            break;
        case AF_INET6:
            inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), dbg, sizeof(dbg));
            port = ((struct sockaddr_in6 *)sa)->sin6_port;
            break;
        default:
            strcpy(dst, "UNKNOWN");
            port = 0;
    }
    printf("============ SOCKET INFORMATION =============\n");
    printf("!** socket: %d\n", sock_fd);
    printf("!** info->ai_addr: sockaddr_in(\n");
    famstr = fam2str(sa->sa_family);
    printf("!**     sa_family:    %s\n", famstr);
    printf("!**     sin[6]_port:  %d\n", ntohs(port));
    printf("!**     sin[6]_addr:  in_addr( s_addr : '%s' )\n", dbg);
    printf("!**)\n");
    printf("=============================================\n");
    return 1;
}
于 2013-01-26T20:05:19.843 に答える