Localhost'ta nasıl ücretsiz bir port numarası seçerim?


161

İşlemler arası iletişim ile oynamaya çalışıyorum ve Windows altında adlandırılmış boruları nasıl kullanacağımı anlayamadığım için ağ soketlerini kullanacağımı düşündüm. Her şey yerel olarak gerçekleşir. Sunucu köleleri ayrı bir işlemde başlatabilir ve bazı bağlantı noktalarını dinleyebilir. Köleler işlerini yaparlar ve sonucu ustaya teslim ederler. Hangi bağlantı noktasının kullanılabilir olduğunu nasıl anlayabilirim? Sanırım 80 ya da 21 numaralı bağlantı noktasını dinleyemiyorum?

Python kullanıyorum, eğer seçimler azalırsa.

Teşekkürler!


1
Bu arada, sadece rastgele veya rastgele bir ish port numarası (tercihen 1024'ten yüksek) seçerseniz, muhtemelen kullanılabilir olacaktır. Başka bir program dinlemediği sürece 80 veya 21 numaralı bağlantı noktasını veya her neyse kullanabilirsiniz. Herhangi bir zamanda, normal bir sistemde, portların sadece küçük bir kısmı kullanılmaktadır.
David Z

19
Rastgele bir bağlantı noktası seçmek iyi bir fikir değildir - işletim sisteminin sizin için bir tane seçmesine izin verin.
Corehpf

Yanıtlar:


225

Belirli bir bağlantı noktasına veya 0 numaralı bağlantı noktasına bağlamayın, örn sock.bind(('', 0)). İşletim sistemi daha sonra sizin için kullanılabilir bir bağlantı noktası seçecektir. Kullanarak seçilen bağlantı noktasını alabilir ve sock.getsockname()[1]geri bağlanabilmeleri için kölelere iletebilirsiniz.


4
Bkz stackoverflow.com/a/2838309/3538289 örneği içinsock.bind(('',0))
cevaris

10
Numarayı kölelere nasıl iletirsiniz? Bana bir tavuk ve yumurta problemi gibi geliyor.
Sebastian

2
Köleler bağlandıktan sonra oluşturulduysa, bunları oluştururken bir parametre olarak iletebilirsiniz. Alternatif olarak, onu paylaşılan bir belleğe veya her ikisinin de erişebileceği bir dosyaya yazabilir veya iyi bilinen bir bağlantı noktası numarasıyla erişilen merkezi bir sunucu bunu izleyebilir.
mark4o

49

Yukarıda açıklananların pasajı uğruna:

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
localhost ise: belki s.bind(('localhost', 0))daha iyidir
codeskyblue

3
Ayrıca aşağıdaki ifadeyi eklemek iyi, böylece iade portunuzdan önce bu portu hızlı bir şekilde tekrar kullanabilirsiniz:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird

1
@jonEbird socket.SO_REUSEADDRBu durumda gerçekten yardımcı oluyor mu ? Okuduğum kadarıyla, sadece bağlanmaya çalışan soketin olması SO_REUSEADDRönemlidir ve bu bayrağın kalan sokette ayarlanıp ayarlanmadığı önemsizdir.
Karl Bartel

41

Soketi 0 bağlantı noktasına bağlayın. 1024 ila 65535 arasında rastgele bir serbest bağlantı noktası seçilecektir. Seçilen bağlantı noktasını getsockname()hemen ardından alabilirsiniz bind().


2

İstediğiniz bağlantı noktasını dinleyebilirsiniz; genellikle, kullanıcı uygulamaları 1024 ve üstü portları dinlemelidir (65535'e kadar). Değişken sayıda dinleyiciniz varsa ana şey, uygulamanıza bir aralık ayırmaktır - örneğin 20000-21000 ve CATCH İSTİSNALARI . Bilgisayarınızda bir bağlantı noktasının kullanılamaz (başka bir işlem tarafından, başka bir deyişle kullanılır) olup olmadığını nasıl öğreneceksiniz.

Ancak, sizin durumunuzda, bağlantı başarısız olursa bir hata mesajı yazdırdığınız sürece dinleyiciniz için tek bir sabit kodlu bağlantı noktası kullanmayla ilgili bir sorununuz olmamalıdır.

Ayrıca, soketlerinizin çoğunun (slave'ler için) açıkça belirli bağlantı noktası numaralarına bağlı olması gerekmediğine dikkat edin - yalnızca gelen bağlantıları (buradaki master'ınız gibi) bekleyen soketlerin dinleyici olması ve bir bağlantı noktasına bağlanması gerekir. Kullanılmadan önce bir soket için bir port belirtilmemişse, OS sokete kullanılabilir bir port atayacaktır. Kaptan veri gönderen bir slave'e yanıt vermek istediğinde, dinleyici veri aldığında gönderenin adresine erişilebilir.

Bunun için UDP kullanacağınızı tahmin ediyorum.


0

Daha sonra kullanmak için yalnızca ücretsiz bir bağlantı noktası bulmanız gerekiyorsa, işte bir önceki cevaba benzer , ancak daha kısa, soket sunucusu kullanarak :

import socketserver

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

Bağlantı noktasının boş kalmasının garanti edilmediğini unutmayın, bu nedenle bu snippet'i ve kodu kullanarak bir döngüye koymanız gerekebilir.

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.