3

IPv6接続とIPv4接続の両方をリッスンするサーバーアプリケーションを作成しようとしています。これを実現する適切な方法は、IPv4接続も受け入れるIPv6アドレスをリッスンしているようです。

関連するコードは次のとおりです。

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, MYPORT, &hints, &res);

(Beejのガイドからほとんどコピーペーストされています)

問題は、少なくとも私のシステムでは、 1番目と2番目getaddrinfoのエントリを返すのに対し、仕様に従って、クライアントが最初に返すことです。私の素朴なアプローチでは、サーバーはIPv4を選択し、クライアントはIPv6を選択し、接続は失敗します。AF_INETAF_INET6getaddrinfoAF_INET6

を設定してこれを修正しようとしましhints.ai_family = AF_INET6たが、IPv6が利用できないシステムでは失敗します。

私は2つの明白な解決策を見ています:
a)最初にIPv6を要求し、それが失敗した場合はIPv4にフォールバックするか、
b)の結果をウォークスルーしgetaddrinfo、IPv6を探し、存在しない場合は最初のエントリを選択し
ますが、私は好きではありませんどちらかが多すぎる;)getaddrinfo正しいことをするように説得する方法、またはおそらく私の目標を達成するための別の方法があるべきだと私は感じています。

4

2 に答える 2

2

返されるアドレスの順序getaddrinfo()は指定されていないため、どちらの場合も処理できるように準備する必要があります。これはおそらく、「これまでに見た最良のアドレス」を追跡しながら、リストをトラバースすることを意味します。

または、によって返されたすべてのアドレスbind()を試してみることもできます。一部のOSは、をリッスンしているIPv6ソケットへのIPv4接続を受け入れないため、これはおそらく最良のオプションです。listen()getaddrinfo()0::0

于 2010-08-24T00:21:06.793 に答える
1

コードは、説明したとおりに機能するはずです。残念ながら、 launchpadのバグ#673708で説明されているように、glibcにはバグがあり、最初にIPv4を選択します。

コンピューター構成ソリューション

サーバープログラムを実行している各Linuxコンピューターで実行できる回避策があります。編集/etc/gai.confし、すべてのデフォルトルールを有効にします(コメントを解除します)。

label ::1/128       0
label ::/0          1
label 2002::/16     2
label ::/96         3
label ::ffff:0:0/96 4
label fec0::/10     5
label fc00::/7      6
label 2001:0::/32   7

それから加えて:

label ::ffff:7f00:1/128 8

次に、サポートされている場合、コードはIPv6を開く必要があり、IPv4接続も受け入れます。

コードソリューション

上記が実用的でない場合(実行するすべてのコンピューターの構成を変更する場合にのみ実用的です)、IPv6を優先するようにコードを変更します。たとえば、私はこれを行いました:

  • 結果を3回通過しgetaddrinfo()ます。
  • 最初のパスは、IPv6を優先します。IPV6_V6ONLYIPv6とIPv4の両方をサポートするためにソケットオプションをクリアしてみてください。
  • 2番目のパスは、IPv4を優先します。
  • 3番目のパス、利用可能なものは何でも取ります。
于 2014-07-10T10:49:43.997 に答える