Linux có tự động dọn sạch các socket miền trừu tượng không?


15

Có một câu trả lời tuyệt vời trên StackOverflow về việc cung cấp khóa tốt hơn cho daemon (được tổng hợp từ Eduardo Fleury ) mà không phụ thuộc vào cơ chế khóa tệp PID phổ biến cho daemon. Có rất nhiều ý kiến ​​hay về việc tại sao các tệp khóa PID đôi khi có thể gây ra sự cố, vì vậy tôi sẽ không thử lại chúng ở đây.

Nói tóm lại, giải pháp dựa vào các socket miền không gian tên trừu tượng của Linux, theo dõi các socket theo tên cho bạn, thay vì dựa vào các tệp, có thể dính xung quanh sau daemon là SIGKILL'd. Ví dụ cho thấy Linux dường như giải phóng ổ cắm một khi quá trình đã chết.

Nhưng tôi không thể tìm thấy tài liệu dứt khoát trong Linux cho biết chính xác Linux làm gì với ổ cắm trừu tượng khi quy trình bị ràng buộc là SIGKILL'd. Có ai biết không?

Nói cách khác, khi chính xác là ổ cắm trừu tượng được giải phóng để được sử dụng lại?

Tôi không muốn thay thế cơ chế tập tin PID bằng các ổ cắm trừu tượng trừ khi nó giải quyết dứt điểm vấn đề.


3
Tôi không thể tìm thấy bất cứ điều gì trả lời trực tiếp. Nhưng vì không có API để loại bỏ các socket trừu tượng, có vẻ như chúng sẽ phải được quản lý tự động bởi kernel. Khi không có quá trình với ổ cắm mở, nó sẽ biến mất.
Barmar

@Barmar Hội chợ đủ rồi. Quan tâm để thêm nó như là một câu trả lời?
CivilFan 20/07/2015

Tôi muốn có nhiều thông tin xác định.
Barmar

Câu trả lời:


5

Có, linux tự động "dọn dẹp" các ổ cắm trừu tượng đến mức làm sạch thậm chí có ý nghĩa. Đây là một ví dụ hoạt động tối thiểu mà bạn có thể xác minh điều này:

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

Chạy chương trình này dưới dạng ./a.out /test-socket &, sau đó chạy ss -ax | grep test-socketvà bạn sẽ thấy ổ cắm đang sử dụng. Sau đó kill %./a.out, và ss -axsẽ hiển thị các ổ cắm đã biến mất.

Tuy nhiên, lý do bạn không thể tìm thấy sự dọn dẹp này trong bất kỳ tài liệu nào là vì nó không thực sự dọn dẹp theo cùng một nghĩa là các ổ cắm không tên miền không trừu tượng cần phải dọn sạch. Một ổ cắm không trừu tượng thực sự phân bổ một nút và tạo một mục trong một thư mục, cần được dọn sạch trong hệ thống tệp bên dưới. Ngược lại, hãy nghĩ về một ổ cắm trừu tượng giống như số cổng TCP hoặc UDP. Chắc chắn, nếu bạn liên kết một cổng TCP và sau đó thoát, cổng TCP đó sẽ lại miễn phí. Nhưng bất cứ số 16 bit nào bạn sử dụng vẫn tồn tại một cách trừu tượng và luôn luôn như vậy. Không gian tên của số cổng là 1-65535 và không bao giờ thay đổi hoặc cần làm sạch.

Vì vậy, chỉ cần nghĩ về tên ổ cắm trừu tượng như số cổng TCP hoặc UDP, chỉ cần chọn từ một tập hợp số cổng lớn hơn nhiều có thể trông giống như tên đường dẫn nhưng không phải. Bạn không thể liên kết cùng một số cổng hai lần (chặn SO_REUSEADDRhoặc SO_REUSEPORT). Nhưng việc đóng ổ cắm (rõ ràng hoặc ngầm định bằng cách chấm dứt) sẽ giải phóng cổng, không còn gì để dọn dẹp.


Nó đã vượt qua bài kiểm tra vịt. Điều đó tốt cho một số thứ, chẳng hạn như python, nhưng tôi mong đợi nhiều hơn cho các tính năng kernel của Linux. Lấy ví dụ về các cổng TCP / UDP của bạn - có rất nhiều tài liệu mô tả chính xác khi nào cổng có thể được sử dụng lại.
CivilFan

2
Và tại sao tài liệu đó không áp dụng như nhau cho các ổ cắm trừu tượng? Bạn đã có một tài liệu tham khảo? Một câu hỏi tốt hơn có thể là nơi mà sự phức tạp làm sạch thêm cho các ổ cắm tên miền Unix không trừu tượng được ghi lại. Trên hệ thống của tôi, đó là bản unix (7) , có nội dung "Linux cũng hỗ trợ một không gian tên trừu tượng, độc lập với hệ thống tệp." Vì vậy, với tôi "độc lập với hệ thống tập tin" ngụ ý không có dọn dẹp dành riêng cho hệ thống tập tin.
dùng3188445

5

Tôi đã đăng câu hỏi này hơn một năm trước và chưa bao giờ hoàn toàn hài lòng với việc thiếu tài liệu dứt khoát. Tôi nghĩ rằng tôi sẽ kiểm tra tài liệu Linux một lần nữa cho bất kỳ bản cập nhật nào và rất vui khi thấy điều này :

Ổ cắm trừu tượng

Quyền truy cập ổ cắm không có ý nghĩa đối với ổ cắm trừu tượng: quy trình umask (2) không có hiệu lực khi ràng buộc ổ cắm trừu tượng và việc thay đổi quyền sở hữu cũng như quyền của đối tượng (thông qua fchown (2) và fchmod (2)) không có hiệu lực đối với khả năng tiếp cận của ổ cắm.

Ổ cắm trừu tượng tự động biến mất khi tất cả các tham chiếu mở đến ổ cắm được đóng lại.

Ngoài ra, Giao diện lập trình Linux của Michael Kerrisk bao gồm câu hỏi (được đăng chéo từ câu trả lời khác này ):

57.6 Không gian tên ổ cắm trừu tượng Linux

Cái gọi là không gian tên trừu tượng là một tính năng dành riêng cho Linux, cho phép chúng ta liên kết một ổ cắm tên miền UNIX với một tên mà không có tên đó được tạo trong hệ thống tệp. Điều này cung cấp một vài lợi thế tiềm năng:

  • Chúng tôi không cần phải lo lắng về các xung đột có thể xảy ra với các tên hiện có trong hệ thống tệp.
  • Không cần thiết phải hủy liên kết tên đường dẫn ổ cắm khi chúng tôi đã sử dụng xong ổ cắm. Tên trừu tượng sẽ tự động bị xóa khi đóng ổ cắm.
  • Chúng ta không cần tạo tên đường dẫn hệ thống tệp cho ổ cắm. Điều này có thể hữu ích trong môi trường chroot hoặc nếu chúng ta không có quyền ghi vào hệ thống tệp.

Để tạo liên kết trừu tượng, chúng tôi chỉ định byte đầu tiên của trường sun_path là byte rỗng (\ 0). [...]

Tôi nghĩ rằng, cùng với câu trả lời của @ user3188445, điều này sẽ xóa câu hỏi rất chính xác.

Điều đó nói rằng, vẫn còn một giả định được đưa ra ở đây, rằng các quy trình SIGKILL sẽ đóng tất cả các ổ cắm mở. Đó có vẻ là một giả định hợp lý, nhưng tôi không có tài liệu xác định hành vi đó.


1
Đoạn cuối: socket là bộ mô tả tập tin và tất cả các bộ mô tả tập tin mở được đóng lại khi một quá trình thoát ra. Tự sướng. Cụ thể hơn, một socket là một tệp đang mở, các tệp đang mở có thể được truyền xung quanh, ví dụ như được kế thừa bởi các tiến trình con. Vì vậy, bạn nên đảm bảo gọi socket với SOCK_CLOEXECtrường hợp bất kỳ mã nào (bao gồm cả thư viện) không bao giờ fork () + exec (). Tạo các tiến trình con bổ sung bằng cách sử dụng fork () mà không có exec () là ít phổ biến hơn; bạn có thể biết nếu bạn đang làm điều đó.
sourcejedi

Không cần thiết phải hủy liên kết ... - ừm, vì không có tên đường dẫn, nên không thể hủy liên kết, không chỉ không cần thiết.
Domen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.