web-dev-qa-db-ja.com

Linuxは抽象ドメインソケットを自動的にクリーンアップしますか?

StackOverflowには、デーモンの一般的なPIDファイルロックメカニズムに依存しない デーモンのロックを向上させるEduardo Fleury から合成)についての素晴らしい答えがあります。 PIDロックファイルが時々問題を引き起こす可能性がある理由についての良いコメントがたくさんあるので、ここではそれらを再度ハッシュしません。

要するに、ソリューションは、デーモンがSIGKILLされた後にとどまることができるファイルに依存するのではなく、ソケットを名前で追跡するLinux抽象名前空間ドメインソケットに依存しています。この例は、プロセスが停止するとLinuxがソケットを解放するように見えることを示しています。

しかし、バインドされたプロセスがSIGKILLされたときに、Linuxが抽象ソケットで正確に何を行うかを説明するLinuxの決定的なドキュメントは見つかりません。誰か知っていますか?

別の言い方をすると、抽象ソケットが解放されて再び使用できるようになるのはいつですか?

問題を明確に解決しない限り、PIDファイルメカニズムを抽象ソケットに置き換えたくありません。

15
CivFan

はい、Linuxは抽象ソケットを自動的に「クリーンアップ」します。これを確認できる最小限の作業例を次に示します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int
main(int argc, char **argv)
{
  int s;
  struct sockaddr_un Sun;

  if (argc != 2 || strlen(argv[1]) + 1 > sizeof(Sun.sun_path)) {
    fprintf(stderr, "usage: %s abstract-path\n", argv[0]);
    exit(1);
  }

  s = socket(AF_UNIX, SOCK_STREAM, 0);
  if (s < 0) {
    perror("socket");
    exit(1);
  }
  memset(&Sun, 0, sizeof(Sun));
  Sun.sun_family = AF_UNIX;
  strcpy(Sun.sun_path + 1, argv[1]);
  if (bind(s, (struct sockaddr *) &Sun, sizeof(Sun))) {
    perror("bind");
    exit(1);
  }
  pause();
}

このプログラムを./a.out /test-socket &として実行し、次にss -ax | grep test-socketを実行すると、使用中のソケットが表示されます。次に、kill %./a.out、およびss -axは、ソケットがなくなったことを示します。

ただし、このクリーンアップがどのドキュメントでも見つからないのは、非抽象unixドメインソケットのクリーンアップが必要なのと同じ意味では、実際のクリーンアップではないためです。非抽象ソケットは、実際にはiノードを割り当て、ディレクトリにエントリを作成します。これは、基礎となるファイルシステムでクリーンアップする必要があります。対照的に、抽象ソケットはTCPまたはUDPポート番号に似ています。確かに、TCPポートをバインドして終了すると、そのTCPポートは再び解放されます。ただし、使用した16ビットの数値は抽象的に存在し、常に存在します。ポート番号の名前空間は1〜65535で、変更したり、クリーニングする必要はありません。

したがって、TCPまたはUDPポート番号のような抽象的なソケット名を考えてみてください。たまたまパス名のように見えるが、そうではない可能性のある非常に大きなポート番号のセットから選択しただけです。同じポート番号を2回バインドすることはできません(SO_REUSEADDRまたはSO_REUSEPORTを除く)。ただし、ソケットを閉じると(明示的または暗黙的に終了することにより)、ポートが解放され、クリーンアップするものがなくなります。

5
user3188445

私は1年以上前にこの質問を投稿しましたが、明確な文書がないことにまったく満足していませんでした。 Linuxのドキュメントで更新がないかもう一度確認するつもりだったので、満足しました これを確認するには

抽象的なソケット

ソケットパーミッションは、抽象ソケットには意味がありません。プロセスumask(2)は、抽象ソケットをバインドするときに効果がなく、オブジェクトの所有権とパーミッションを変更すると(fchown(2)とfchmod(2)を介して)、ソケットのアクセシビリティ。

抽象的なソケットは、ソケットへの開いている参照がすべて閉じられると、自動的に消えます。

また、 The Linux Programming Interface by Michael Kerrisk が質問をカバーしています(- this other answer ):

57.6 Linux抽象ソケット名前空間

いわゆる抽象名前空間はLinux固有の機能であり、ファイルシステムでその名前を作成しなくても、UNIXドメインソケットをその名前にバインドできます。これには、いくつかの潜在的な利点があります。

  • ファイルシステム内の既存の名前との衝突の可能性について心配する必要はありません。
  • ソケットの使用を終了したときに、ソケットのパス名をリンク解除する必要はありません。ソケットを閉じると、抽象名は自動的に削除されます。
  • ソケットのファイルシステムパス名を作成する必要はありません。これは、chroot環境で、またはファイルシステムへの書き込みアクセス権がない場合に役立ちます。

抽象バインディングを作成するには、Sun_pathフィールドの最初のバイトをnullバイト(\ 0)として指定します。 [...]

@ user3188445の回答とともに、これにより質問が非常に正確に解決されたと思います。

そうは言っても、ここで行われた仮定はまだあります。SIGKILLされるプロセスは、開いているすべてのソケットを閉じることになります。それは妥当な仮定のようですが、その動作を定義するドキュメントはありません。

5
CivFan