2

実際、IPv4 サーバー アプリケーションを Linux 上のデュアルスタック IPv4/IPv6 アプリケーションに移植しています。

私が使用して解決した基本的な機能:

serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_addr = in6addr_any;
...
bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
...
listen(sock, 5);
...
newsock = accept(syn->sock, (struct sockaddr *) &cli_addr, &clilen);

IPv4 と IPv6 で接続でき、接続を使用できます。しかし、IPを取得したい場合:

switch(data->sa_family) {
   case AF_INET:
   inet_ntop(AF_INET, &(((struct sockaddr_in*)data)->sin_addr), buffer, size);
   break;
   case AF_INET6:
   inet_ntop(AF_INET6, &(((struct sockaddr_in6*)data)->sin6_addr), buffer, size);
   break;

   default:
   buffer[0] = '?';
   buffer[1] = 0;
}

期待どおりに常にIPv6アドレスを取得します。または、IPv4接続の場合は::ffff:127.0.0.1のようなものです

127.0.0.1 (::ffff:-prefix なし) の形式でプレーンな古い IPv4 アドレスとして表示するには、何を変更する必要がありますか?

ありがとうテディ

4

3 に答える 3

2

役立つマクロがありますが、戦いは半分に過ぎません。

  if (IN6_IS_ADDR_V4MAPPED(&serv_addr.sin6_addr)) {
        struct sockaddr_in tmpsa;
        tmpsa.sin_family = AF_INET;
        tmpsa.sin_port = 0;
        tmpsa.sin_addr.s_addr = serv_addr.sin6_addr.s6_addr32[3];
  /* process IPv4 address in tmpsa ... */
        inet_ntop (AF_INET, &tmpsa.sin_addr, buffer, size);
  } else {
  /* process IPv6 address in serv_addr.. */
        inet_ntop (AF_INET6, &serv_addr.sin6_addr, buffer, size);
  }

プラットフォームによっては若干の変更が必要になる場合があります。ここでは GNU 標準を使用します。

于 2012-12-19T17:19:48.583 に答える
1

次のようなコードを使用して、IPv4 マップ接続を実際に IPv4 であるかのように表示するように要求します。

int cli = accept( server, NULL, NULL );
int addrform = AF_INET;
setsockopt( cli, IPPROTO_IPV6, IPV6_ADDRFORM, &addrform, sizeof(addrform) );

これは、新しいクライアント ソケットごとに実行する必要があります。IPv6 接続では失敗します。それを無視するか、最初に確認して、IPv4 マップされたクライアントを使用している場合にのみ呼び出すことができます。

これが完了すると、 を呼び出しgetpeername()て、 を呼び出すのではなく、 を呼び出して、クライアント アドレス情報を優先形式で取得できますaccept()

于 2012-12-19T16:55:21.067 に答える
1

次の 2 つの方法があります。

  1. 存在する場合は、最初からこれを取り除き::ffff:、IPv4 の指標として使用してください。

  2. 2 つの異なるソケットを使用します。1 つのソケットを介して IPv4 および 6 をサポートしない OS がそこら中にあります (IOW、それらはV6ONLY常に有効になっています)。特に、WinXP はそうします。

    次に、できることは 1 つだけです。

    • 持つことができるすべてのローカルソケットアドレスを取得するためにgetaddrinfo()withを使用しますAI_PRIVATE
    • それらすべてを使用してリッスン ソケットを作成し、V6ONLY可能であればすぐに有効にします
    • それらの記述子を配列に保持し、select()et al を使用してそれらのどれを呼び出すかを決定しますaccept()

    実際よりも複雑に聞こえます...

于 2012-12-19T10:19:22.330 に答える