2011-09-13 38 views
29

Tôi đang viết một máy chủ socket miền Unix cho Linux.Làm cách nào để biết liệu có quá trình nào bị ràng buộc với một ổ cắm miền Unix không?

Tính đặc thù của ổ cắm miền Unix Tôi nhanh chóng phát hiện ra rằng, trong khi tạo ổ cắm Unix đang nghe tạo mục nhập hệ thống tệp phù hợp, đóng chốt không loại bỏ nó. Hơn nữa, cho đến khi mục nhập hệ thống tập tin được gỡ bỏ thủ công, không thể để bind() một ổ cắm vào cùng một đường dẫn nữa: bind() không thành công với EADDRINUSE nếu đường dẫn được đưa ra đã tồn tại trong hệ thống tệp.

Kết quả là, mục nhập hệ thống tệp của socket cần phải được tắt unlink() 'bật tắt máy chủ để tránh bị EADDRINUSE khởi động lại máy chủ. Tuy nhiên, điều này không phải lúc nào cũng được thực hiện (nghĩa là: máy chủ bị lỗi). Hầu hết các câu hỏi thường gặp, bài đăng trên diễn đàn, Q & Một trang web tôi đã tìm thấy chỉ tư vấn, như một giải pháp, để unlink() ổ cắm trước khi gọi bind(). Trong trường hợp này tuy nhiên, nó trở nên mong muốn để biết liệu một quá trình được ràng buộc vào ổ cắm này trước khi unlink() 'ing nó.

Thực tế, unlink() 'đang nhập một ổ cắm Unix trong khi quá trình vẫn bị ràng buộc với nó và sau đó tạo lại ổ cắm nghe không gây ra bất kỳ lỗi nào. Kết quả là, tuy nhiên, quá trình máy chủ cũ vẫn chạy nhưng không thể truy cập được: ổ cắm nghe cũ được "đeo" bởi ổ cắm mới. Hành vi này phải được tránh. Lý tưởng nhất là, bằng cách sử dụng các ổ cắm miền Unix, API socket nên tiếp xúc với cùng một hành vi "loại trừ lẫn nhau" được tiếp xúc khi gắn các cổng TCP hoặc UDP: "Tôi muốn kết nối socket S với địa chỉ A; đã bị ràng buộc với địa chỉ này, chỉ cần khiếu nại! "Rất tiếc, đây không phải là trường hợp ...

Có cách nào để thực thi hành vi" loại trừ lẫn nhau "này không? Hoặc, với một đường dẫn hệ thống tập tin, có cách nào để biết, thông qua API socket, cho dù bất kỳ quá trình nào trên hệ thống đều có một ổ cắm miền Unix được liên kết với đường dẫn này không? Tôi có nên sử dụng đồng bộ hóa nguyên thủy bên ngoài với API socket (flock(), ...) không? Hay tôi đang thiếu một cái gì đó?

Cảm ơn đề xuất của bạn.

Lưu ý: Không gian tên trừu tượng của Linux Các ổ cắm Unix dường như giải quyết vấn đề này, vì không có mục nhập hệ thống tệp nào vào unlink(). Tuy nhiên, máy chủ tôi đang viết nhằm mục đích là chung chung: nó phải mạnh mẽ chống lại cả hai loại ổ cắm miền Unix, vì tôi không chịu trách nhiệm về việc chọn địa chỉ nghe.

Trả lời

18

Tôi biết tôi rất muộn với bên và điều này đã được trả lời từ lâu nhưng tôi chỉ gặp phải điều này khi tìm kiếm một thứ khác và tôi có đề xuất thay thế.

Khi bạn gặp trả lại EADDRINUSE từ bind() bạn có thể nhập lỗi kiểm tra thường trình kết nối với ổ cắm. Nếu kết nối thành công, có một quy trình đang hoạt động ít nhất đủ để thực hiện accept(). Điều này đánh tôi như là cách đơn giản và di động nhất để đạt được những gì bạn muốn đạt được. Nó có nhược điểm ở chỗ máy chủ tạo UDS ở nơi đầu tiên có thể vẫn đang chạy nhưng "bị kẹt" bằng cách nào đó và không thể thực hiện được accept(), vì vậy giải pháp này chắc chắn không phải là chống lừa đảo, nhưng đó là một bước trong đúng hướng tôi nghĩ.

Nếu số connect() không thành công thì hãy tiếp tục và unlink() điểm cuối và thử lại bind().

9

Tôi không nghĩ có nhiều việc phải làm ngoài những thứ bạn đã cân nhắc. Bạn dường như đã nghiên cứu nó tốt. Có nhiều cách để xác định xem một ổ cắm có bị ràng buộc với một ổ cắm unix (rõ ràng là lsof và netstat làm điều đó) nhưng chúng phức tạp và đủ phụ thuộc vào hệ thống mà tôi đặt câu hỏi liệu chúng có đáng để xử lý các vấn đề bạn nêu ra hay không. .

Bạn đang thực sự gây ra hai vấn đề - xử lý các xung đột tên với các ứng dụng khác và xử lý các phiên bản trước đó của ứng dụng của riêng bạn.

Theo định nghĩa nhiều trường hợp pgm của bạn không nên cố gắng liên kết với cùng một đường dẫn để có thể có nghĩa là bạn chỉ muốn một cá thể chạy cùng một lúc. Nếu đó là trường hợp bạn chỉ có thể sử dụng kỹ thuật filelock pid chuẩn để hai trường hợp không chạy đồng thời. Bạn không nên hủy liên kết ổ cắm hiện tại hoặc thậm chí chạy nếu bạn không thể lấy khóa. Thao tác này cũng sẽ xử lý kịch bản lỗi máy chủ.Nếu bạn có thể lấy khóa thì bạn biết bạn có thể hủy liên kết đường dẫn socket hiện có trước khi liên kết.

Không có nhiều bạn có thể làm AFAIK để kiểm soát các chương trình khác tạo ra xung đột. Quyền đối với tệp không hoàn hảo, nhưng nếu tùy chọn có sẵn cho bạn, bạn có thể đặt ứng dụng của mình vào nhóm/người dùng của riêng nó. Nếu có một đường dẫn socket hiện có và bạn không sở hữu nó thì đừng hủy liên kết nó và đưa ra một thông báo lỗi và cho phép người dùng hoặc sysadmin phân loại nó ra. Sử dụng một tập tin cấu hình để làm cho nó dễ dàng thay đổi - và có sẵn cho khách hàng - có thể làm việc. Ngoài ra bạn hầu như phải đi một loại dịch vụ khám phá nào đó, có vẻ như quá mức cần thiết trừ khi đây là một ứng dụng thực sự quan trọng.

Nói chung, bạn có thể thoải mái rằng điều này không thực sự xảy ra thường xuyên.

+0

Cảm ơn câu trả lời của bạn. Sử dụng một hệ thống lockfile truyền thống được thừa nhận là cách an toàn nhất để đi. Ngoài ra, để biết liệu một hệ thống phát hiện dịch vụ có quá tải hay không: trớ trêu thay, máy chủ này được dự định là một phần của hệ thống khám phá dịch vụ (hệ thống "đăng ký" dịch vụ có vẻ phù hợp hơn). Điêu nay co thể trả lơi câu hỏi của bạn ;-) –

Các vấn đề liên quan