Linux soyut etki alanı soketlerini otomatik olarak temizliyor mu?


15

StackOverflow'da, cinler için ortak PID dosya kilidi mekanizmasına bağlı olmayan , cinler için daha iyi bir kilit ( Eduardo Fleury'den sentezlenmiş ) sağlama konusunda harika bir cevap var . PID kilit dosyalarının neden bazen sorunlara neden olabileceği konusunda çok sayıda iyi yorum var, bu yüzden onları burada yeniden düzenlemeyeceğim.

Kısacası, çözüm, arka planın SIGKILL'd olduktan sonra etrafta durabilen dosyalara güvenmek yerine, soketleri sizin adınıza takip eden Linux soyut ad alanı etki alanı soketlerine dayanıyor. Örnekte, işlem bittiğinde Linux'un soketi serbest bıraktığı görülüyor.

Ancak, bağlı süreç SIGKILL'd olduğunda Linux'un soyut soketle tam olarak ne yaptığını söyleyen kesin dokümanları Linux'ta bulamıyorum. Kimse biliyor mu?

Başka bir deyişle, soyut soket ne zaman tekrar kullanılmak üzere serbest bırakılır?

Sorunu kesin olarak çözmediği sürece PID dosya mekanizmasını soyut soketlerle değiştirmek istemiyorum.


3
Buna doğrudan cevap veren bir şey bulamıyorum. Ancak soyut soketleri kaldırmak için API olmadığı için, çekirdek tarafından otomatik olarak yönetilmeleri gerektiği anlaşılıyor. Soket açıkken hiçbir işlem olmadığında, gitmelidir.
Barmar

@Barmar Yeterince adil. Cevap olarak eklemek ister misiniz?
CivFan

Daha kesin bilgiye sahip olmayı tercih ederim.
Barmar

Yanıtlar:


5

Evet, linux, temizlemenin anlamlı olduğu ölçüde soyut soketleri otomatik olarak "temizler". İşte bunu doğrulayabileceğiniz minimal bir çalışma örneği:

#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();
}

Bu programı şu şekilde ./a.out /test-socket &çalıştırın, sonra çalıştırın ss -ax | grep test-socketve kullanılan soketi göreceksiniz. Ardından kill %./a.out, ve ss -axsoket gitmiş olduğunu gösterecektir.

Bununla birlikte, bu temizlemeyi herhangi bir belgede bulamamanızın nedeni, soyut olmayan unix alan soketlerinin temizlenmesi gerektiği ile aynı anlamda temizlenmemesidir. Soyut olmayan bir soket aslında bir inode tahsis eder ve bir dizinde temel dosya sisteminde temizlenmesi gereken bir girdi oluşturur. Buna karşılık, soyut bir soketi daha çok TCP veya UDP bağlantı noktası numarası gibi düşünün. Elbette, bir TCP bağlantı noktasını bağlarsanız ve sonra çıkarsanız, o TCP bağlantı noktası tekrar boş olacaktır. Ama kullandığınız 16 bitlik sayı ne olursa olsun hala soyut ve her zaman var. Bağlantı noktası numaralarının ad alanı 1-65535'tir ve hiçbir zaman değişmez veya temizlenmesi gerekmez.

Bu nedenle, soyut soket adını bir TCP veya UDP port numarası gibi düşünün, sadece yol adları gibi görünen ancak daha büyük olası port numaraları kümesinden seçildi. Aynı bağlantı noktası numarasını iki kez bağlayamazsınız (engelleme SO_REUSEADDRveya SO_REUSEPORT). Ancak soketi kapatmak (açıkça veya dolaylı olarak sonlanarak) bağlantı noktasını serbest bırakır ve temizlenmesi gereken bir şey kalmaz.


Ördek testini geçti bile. Python gibi bazı şeyler için bu iyi, ama Linux çekirdek özellikleri için daha fazlasını bekliyorum. TCP / UDP bağlantı noktalarına örnek alın; bağlantı noktasının ne zaman tekrar kullanılabileceğini açıklayan çok sayıda belge vardır.
CivFan

2
Ve bu belgeler neden soyut soketler için eşit olarak geçerli değil? Referansınız var mı? Daha iyi bir soru, soyut olmayan Unix alan soketleri için ekstra temizleme komplikasyonunun belgelendiği olabilir. Sistemimde bu, "Linux ayrıca dosya sisteminden bağımsız soyut bir ad alanını da destekler" yazan unix (7) ' de. Yani bana göre "dosya sisteminden bağımsız" hiçbir dosya sistemine özgü temizleme anlamına gelmez.
user3188445

5

Bu soruyu bir yıl önce yayınladım ve kesin dokümantasyon eksikliğinden hiçbir zaman memnun kalmadım. Herhangi bir güncelleme için Linux belgelerini tekrar kontrol edeceğimi düşündüm ve bunu gördüğüme sevindim :

Soyut yuva

Soket izinlerinin soyut soketler için bir anlamı yoktur: umask (2) işleminin soyut bir soketi bağlarken ve nesnenin sahipliğini ve izinlerini değiştirirken (fchown (2) ve fchmod (2) aracılığıyla) bir etkisi yoktur. soketin erişilebilirliği.

Sokete yapılan tüm açık referanslar kapatıldığında soyut soketler otomatik olarak kaybolur.

Ayrıca, Michael Kerrisk tarafından yapılan Linux Programlama Arayüzü şu soruyu da kapsıyor ( bu diğer cevaptan çapraz olarak yayınlanmıştır ):

57.6 Linux Soyut Soket Ad Alanı

Özet ad alanı, UNIX etki alanı soketini, dosya sisteminde bu ad oluşturulmadan bir ada bağlayabilmemizi sağlayan Linux'a özgü bir özelliktir. Bu birkaç potansiyel avantaj sağlar:

  • Dosya sistemindeki mevcut adlarla olası çarpışmalar konusunda endişelenmemize gerek yoktur.
  • Soketi kullanmayı bitirdiğimizde soket yol adının bağlantısını kaldırmaya gerek yoktur. Soyut ad, soket kapatıldığında otomatik olarak kaldırılır.
  • Soket için bir dosya sistemi yol adı oluşturmamız gerekmez. Bu, bir chroot ortamında veya bir dosya sistemine yazma erişimimiz yoksa faydalı olabilir.

Soyut bir bağlayıcı oluşturmak için sun_path alanının ilk baytını boş bayt (\ 0) olarak belirtiriz . [...]

@ User3188445'in yanıtıyla birlikte, sorunun çok net bir şekilde ortadan kaldırıldığını tahmin ediyorum.

Bununla birlikte, burada hala bir varsayım var, SIGKILL olan süreçlerin tüm açık soketlerin kapalı olacağına dair. Bu makul bir varsayım gibi görünüyor, ancak bu davranışı tanımlayan belgelerim yok.


1
Son paragraf yeniden: soketler dosya tanımlayıcılarıdır ve bir işlem çıktığında tüm açık dosya tanımlayıcıları kapatılır. Ish. Daha spesifik olarak, bir soket açık bir dosyadır, açık dosyalar örneğin alt süreçler tarafından miras alınabilir. Bu nedenle SOCK_CLOEXECherhangi bir kodun (kütüphane dahil) fork () + exec () yapması durumunda soketi mutlaka aramalısınız . Exec () olmadan fork () kullanarak ekstra alt süreçler oluşturmak daha az yaygındır; muhtemelen bunu zaten yapıp yapmadığınızı biliyorsunuzdur.
sourcejedi

Bağlantıyı kaldırmak gerekli değildir ... - um, yol adı olmadığından bağlantıyı kaldırmak mümkün değildir, sadece gereksiz değildir.
domen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.