Trên localhost, làm cách nào để chọn số cổng miễn phí?


160

Tôi đang cố gắng chơi với giao tiếp giữa các quá trình và vì tôi không thể tìm ra cách sử dụng các đường ống có tên trong Windows, tôi nghĩ tôi sẽ sử dụng các ổ cắm mạng. Mọi thứ xảy ra cục bộ. Máy chủ có thể khởi chạy nô lệ trong một quy trình riêng và lắng nghe trên một số cổng. Các nô lệ làm công việc của họ và gửi kết quả cho chủ. Làm thế nào để tôi tìm ra cổng nào có sẵn? Tôi cho rằng tôi không thể nghe trên cổng 80 hoặc 21?

Tôi đang sử dụng Python, nếu điều đó cắt giảm các lựa chọn.

Cảm ơn!


1
Ngẫu nhiên, nếu bạn chỉ chọn một số cổng ngẫu nhiên hoặc ngẫu nhiên (tốt nhất là cao hơn 1024), nó có thể sẽ khả dụng. Bạn thậm chí có thể sử dụng cổng 80 hoặc 21 hoặc bất cứ điều gì, miễn là không có chương trình nào khác nghe trên đó. Tại bất kỳ thời điểm nào, trên một hệ thống bình thường, chỉ một phần nhỏ các cổng được sử dụng.
David Z

19
Chọn một cổng ngẫu nhiên không phải là một ý tưởng hay - hãy để HĐH chọn một cổng cho bạn.
Corehpf

Câu trả lời:


224

Không liên kết với một cổng cụ thể hoặc liên kết với cổng 0, ví dụ sock.bind(('', 0)). Hệ điều hành sau đó sẽ chọn một cổng có sẵn cho bạn. Bạn có thể lấy cổng được chọn bằng cách sử dụng sock.getsockname()[1]và chuyển nó cho các nô lệ để họ có thể kết nối lại.


4
Xem stackoverflow.com/a/2838309/3538289 để biết ví dụ vềsock.bind(('',0))
cevaris

10
Làm thế nào để bạn truyền số cho nô lệ? Âm thanh như một vấn đề gà và trứng với tôi.
Sebastian

2
Nếu các nô lệ được tạo sau khi ràng buộc, bạn có thể chuyển nó dưới dạng tham số khi tạo chúng. Ngoài ra, bạn có thể ghi nó vào một số bộ nhớ dùng chung hoặc một tệp mà cả hai có thể truy cập hoặc một máy chủ trung tâm được truy cập thông qua một số cổng nổi tiếng có thể theo dõi nó.
mark4o

49

Vì lợi ích của những gì các chàng trai đã giải thích ở trên:

import socket
from contextlib import closing

def find_free_port():
    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
        s.bind(('', 0))
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        return s.getsockname()[1]

3
nếu trên localhost: có thể s.bind(('localhost', 0))tốt hơn
codkyblue

3
Cũng tốt để thêm các mục sau để bạn có thể nhanh chóng sử dụng lại cổng đó trước tuyên bố trở lại của mình:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird

1
@jonEbird Có socket.SO_REUSEADDRthực sự giúp ích trong trường hợp này? Từ những gì tôi đọc được, chỉ có liên quan rằng ổ cắm đang cố gắng liên kết có SO_REUSEADDRvà không liên quan cho dù cờ đó được đặt trên ổ cắm còn sót lại.
Karl Bartel

41

Liên kết ổ cắm với cổng 0. Một cổng miễn phí ngẫu nhiên từ 1024 đến 65535 sẽ được chọn. Bạn có thể lấy lại cổng đã chọn getsockname()ngay sau đó bind().


2

Bạn có thể nghe trên bất cứ cổng nào bạn muốn; nói chung, các ứng dụng người dùng nên nghe các cổng 1024 trở lên (đến 65535). Điều chính nếu bạn có số lượng người nghe thay đổi là phân bổ một phạm vi cho ứng dụng của bạn - giả sử 20000-21000 và CATCH EXCEPTION . Đó là cách bạn sẽ biết nếu một cổng không sử dụng được (được sử dụng bởi một quy trình khác, nói cách khác) trên máy tính của bạn.

Tuy nhiên, trong trường hợp của bạn, bạn không nên gặp sự cố khi sử dụng một cổng được mã hóa cứng cho người nghe, miễn là bạn in thông báo lỗi nếu liên kết không thành công.

Cũng lưu ý rằng hầu hết các ổ cắm của bạn (đối với nô lệ) không cần phải bị ràng buộc rõ ràng với số cổng cụ thể - chỉ các ổ cắm chờ kết nối đến (như chủ của bạn ở đây) sẽ cần phải được nghe và ràng buộc với một cổng. Nếu một cổng không được chỉ định cho một ổ cắm trước khi nó được sử dụng, HĐH sẽ chỉ định một cổng có thể sử dụng cho ổ cắm. Khi chủ muốn trả lời một nô lệ gửi dữ liệu đó, địa chỉ của người gửi có thể truy cập được khi người nghe nhận dữ liệu.

Tôi đoán bạn sẽ sử dụng UDP cho việc này?


0

Nếu bạn chỉ cần tìm một cổng miễn phí để sử dụng sau, đây là đoạn mã tương tự như câu trả lời trước , nhưng ngắn hơn, sử dụng socketserver :

import socketserver

with socketserver.TCPServer(("localhost", 0), None) as s:
    free_port = s.server_address[1]

Lưu ý rằng cổng không được đảm bảo duy trì miễn phí, vì vậy bạn có thể cần đặt đoạn mã này và mã sử dụng nó trong một vòng lặp.

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.