26

事実

POSIX のドキュメントでは、UNIX ドメイン ソケットでのSO_REUSEADDRソケット オプションの使用を妨げるものは何もありません。AF_UNIX

ただし、bindソケットノードがすでに存在し、無視されているように見え、呼び出しの前に最初にファイルシステム上のソケットノードのリンクを解除する必要があるように見える場合、必ず失敗しますbind。つまり、アドレスを再利用しません。この問題に関するスレッドはウェブ上にたくさんありますが、解決策はありません。

質問

うまくいかない場合はうまくいかないとは言いません (少なくとも BSD システムと Linux システムの両方で同じようです)。それがサポートされるべきであることを示唆する指針はありますか、それとも反対に、サポートされるべきではないことを示唆する指針はありますか? それとも、これは指定されていませんか?質問は、特定のプラットフォームのコンテキストではなく、POSIX のコンテキストで行われることに注意してください。

この問題に関する POSIX リファレンスを歓迎します。

unlinkおまけ:誰が何を知っているかをやみくもにしないための小さなスニペット

私はウェブ上でいくつかのスレッドを見てきましunlinkbind. 安全ではないと感じます。この場合、すでにソケットノードであるノードのみをリンク解除する必要があります。mysocketという名前のテキスト ファイルのリンクを解除して、同じ名前のソケット ノードを適切な場所に再作成するのは、おそらく間違っています。この目的のための小さなスニペットを次に示します。

/* Create the socket node
 * ----------------------
 * Note `SO_REUSEADDR` does not work with `AF_UNIX` sockets,
 * so we will have to unlink the socket node if it already exists,
 * before we bind. For safety, we won't unlink an already existing node
 * which is not a socket node. 
 */

status = stat (path, &st);
if (status == 0) {
   /* A file already exists. Check if this file is a socket node.
    *   * If yes: unlink it.
    *   * If no: treat it as an error condition.
    */
   if ((st.st_mode & S_IFMT) == S_IFSOCK) {
      status = unlink (path);
      if (status != 0) {
         perror ("Error unlinking the socket node");
         exit (1);
      }
   }
   else {
      /* We won't unlink to create a socket in place of who-know-what.
       * Note: don't use `perror` here, as `status == 0` (this is an
       * error we've defined, not an error returned by a system-call).
       */
      fprintf (stderr, "The path already exists and is not a socket node.\n");
      exit (1);
   }
}
else {
   if (errno == ENOENT) {
      /* No file of the same path: do nothing. */
   }
   else {
      perror ("Error stating the socket node path");
      exit (1);
   }
}

/* … invoke `bind` here, which will create the socket node … */
4

1 に答える 1

35

System Interfacesという 1 つの POSIX 仕様ドキュメントにしかアクセスできないので、ここから最善を尽くします。

私たちの仕様の探検の冒険は、もちろん2.10.6 オプションの使用 でSO_REUSEADDR開始する必要があり、オプションは次のように定義されています。

SO_REUSEADDR オプションは、bind() で提供されたアドレスの検証に使用されるルールが、ローカル アドレスの再利用を許可する必要があることを示します。このオプションの操作はプロトコル固有です。SO_REUSEADDR のデフォルト値はオフです。つまり、ローカル アドレスの再利用は許可されていません。

このパラグラフは、基本的に、このオプションが実際に何をするかについての仕様を否認し、それを基礎となるプロトコルの仕様に委譲します。

セクション 2.10.17 ローカル UNIX 接続のためのソケットの使用では、UNIX ドメイン ソケットを作成する仕組みについて説明していますが、実際には、どのソケット タイプの定数を使用し、どの構造体をアドレスに使用するかを教えてくれるだけです。構造体のドキュメントでは、sockaddr_un構造体での動作についてではなく、その形式についてのみ説明していますbind

bindそれ自体のドキュメントは当然のことながらプロトコルにとらわれず、同じソケットの再バインドが有効な状況ではなく、アドレスが既に使用されている場合に何が起こるかのみを示しています。

これは POSIX 標準ドキュメントではありませんが、Fujitsu はPOSIX ソケット API に関するドキュメントを持っています。これは、特に Linux や BSD に関するものではないという理由だけで興味深いものです。bindこのドキュメントのセクション 2.6.4 では、 UNIX ソケットでの の動作について次のように述べています。

コンポーネントで指定する必要があるパス名は、 をsun.sun_path使用してファイル システムにファイルとして作成されますbind()。したがって、呼び出すプロセスにはbind()、ファイルが書き込まれるディレクトリへの書き込み権限が必要です。システムはファイルを削除しません。したがって、不要になった時点でプロセスによって削除する必要があります。

SO_REUSEADDRこれは特に何も述べていませんが、 の動作はファイルbind作成することであり、使用されなくなったときにそれを削除するのはバインド プロセスの責任であると述べています。

最後に、このドキュメントの の説明でsetsockoptは、 について次のように述べていますSO_REUSEADDR

bind() に指定されたアドレスの有効性チェックの規則が、プロトコルでサポートされている場合に、ローカル アドレスの再利用を許可する必要があることを指定します。

したがって、これは について特に言及しAF_UNIXていませんが、このオプションがすべてのプロトコルに適用されるわけではないことを認めています。

の意図された目的を説明している(正式なものではない)要約SO_REUSEADDRも見つけました。

このソケット オプションは、このポートが使用中 (TIME_WAIT状態) であっても、先に進んで再利用することをカーネルに伝えます。ビジー状態で別の状態の場合でも、アドレスが既に使用されているというエラーが発生します。

このTIME_WAIT状態は、主にインターネットに面したソケットに対して存在し、最近別のプログラムによって使用されていたポートに新しいプログラムがバインドされ、古いプログラムに関連するパケットを誤って受信することを回避します。2 つのプログラムが同じパスにソケットを作成しようとする可能性は非常に低いため、この問題は UNIX ドメイン ソケットには当てはまりませんTIME_WAITSO_REUSEADDRには適用されませんAF_UNIX

于 2013-03-30T09:55:50.447 に答える