บน localhost ฉันจะเลือกหมายเลขพอร์ตฟรีได้อย่างไร


161

ฉันพยายามเล่นด้วยการสื่อสารระหว่างกระบวนการและเนื่องจากฉันไม่สามารถหาวิธีใช้ไพพ์ที่มีชื่อใน Windows ฉันคิดว่าฉันจะใช้ซ็อกเก็ตเครือข่าย ทุกอย่างเกิดขึ้นในท้องถิ่น เซิร์ฟเวอร์สามารถเรียกใช้ทาสในกระบวนการที่แยกจากกันและฟังในบางพอร์ต พวกทาสทำงานและส่งผลให้นาย ฉันจะทราบได้อย่างไรว่าพอร์ตใดพร้อมใช้งาน ฉันคิดว่าฉันไม่สามารถฟังพอร์ต 80 หรือ 21 ได้

ฉันกำลังใช้ Python ถ้ามันลดตัวเลือกลง

ขอบคุณ!


1
อนึ่งหากคุณเพิ่งเลือกหมายเลขพอร์ตแบบสุ่มหรือแบบสุ่ม - ไอช (สูงกว่า 1024) มันอาจจะใช้ได้ คุณสามารถใช้พอร์ต 80 หรือ 21 หรืออะไรก็ได้ตราบใดที่ไม่มีโปรแกรมอื่นกำลังฟังอยู่ ณ เวลาใดก็ตามบนระบบปกติมีการใช้งานพอร์ตเพียงเล็กน้อยเท่านั้น
David Z

19
การเลือกพอร์ตสุ่มไม่ใช่ความคิดที่ดี - ให้ระบบปฏิบัติการเลือกให้คุณ
Corehpf

คำตอบ:


225

ไม่ผูกเข้ากับพอร์ตที่เฉพาะเจาะจงหรือผูกเข้ากับพอร์ต 0 sock.bind(('', 0))เช่น ระบบปฏิบัติการจะเลือกพอร์ตที่มีให้สำหรับคุณ คุณสามารถรับพอร์ตที่เลือกใช้sock.getsockname()[1]และส่งต่อไปยังทาสเพื่อให้พวกเขาสามารถเชื่อมต่อกลับได้


4
ดูstackoverflow.com/a/2838309/3538289สำหรับตัวอย่างของsock.bind(('',0))
cevaris

10
คุณจะส่งผ่านหมายเลขไปยังทาสได้อย่างไร ฟังดูเหมือนปัญหาเรื่องไก่และไข่สำหรับฉัน
เซบาสเตียน

2
หากทาสถูกสร้างขึ้นหลังจากที่มีผลผูกพันคุณก็สามารถส่งมันเป็นพารามิเตอร์เมื่อสร้างพวกเขา หรือคุณสามารถเขียนลงในหน่วยความจำที่แชร์หรือไฟล์ที่ทั้งสองสามารถเข้าถึงได้หรือเซิร์ฟเวอร์กลางที่เข้าถึงผ่านหมายเลขพอร์ตที่รู้จักกันดีบางตัวสามารถติดตามได้
mark4o

49

เพื่อตัวอย่างของสิ่งที่พวกเขาอธิบายไว้ข้างต้น:

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: อาจs.bind(('localhost', 0))จะดีกว่า
รหัสกี้บลู

3
นอกจากนี้ยังเป็นการดีที่จะเพิ่มสิ่งต่อไปนี้เพื่อให้คุณสามารถใช้พอร์ตนั้นอีกครั้งได้อย่างรวดเร็วก่อนที่ข้อความสั่งการส่งคืนของคุณ:s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
jonEbird

1
@jonEbird มีsocket.SO_REUSEADDRประโยชน์ในกรณีนี้จริงหรือ จากสิ่งที่ฉันอ่านมีความเกี่ยวข้องเฉพาะกับซ็อกเก็ตที่พยายามเชื่อมโยงSO_REUSEADDRและไม่เกี่ยวข้องว่ามีการตั้งค่าสถานะนั้นบนซ็อกเก็ตที่เอ้อระเหย
Karl Bartel

41

ผูกซ็อกเก็ตเข้ากับพอร์ต 0 พอร์ตสุ่มจาก 1024 ถึง 65535 จะถูกเลือก คุณอาจจะดึงพอร์ตที่เลือกด้วยหลังจากที่เหมาะสมgetsockname()bind()


2

คุณสามารถฟังพอร์ตอะไรก็ได้ที่คุณต้องการ โดยทั่วไปแอปพลิเคชันผู้ใช้ควรฟังพอร์ต 1024 ขึ้นไป (ผ่าน 65535) สิ่งที่สำคัญถ้าคุณมีจำนวนตัวแปรของผู้ฟังคือการจัดสรรช่วงแอปของคุณ - พูด 20,000-21,000 และข้อยกเว้นที่จับได้ นี่คือวิธีที่คุณจะรู้ว่าพอร์ตนั้นไม่สามารถใช้งานได้ (ใช้โดยกระบวนการอื่นในคำอื่น ๆ ) บนคอมพิวเตอร์ของคุณ

อย่างไรก็ตามในกรณีของคุณคุณไม่ควรมีปัญหาในการใช้พอร์ตฮาร์ดโค้ดเดียวสำหรับผู้ฟังตราบใดที่คุณพิมพ์ข้อความแสดงข้อผิดพลาดหากการผูกล้มเหลว

โปรดทราบว่าซ็อกเก็ตส่วนใหญ่ของคุณ (สำหรับทาส) ไม่จำเป็นต้องผูกติดกับหมายเลขพอร์ตเฉพาะ - ซ็อกเก็ตเท่านั้นที่รอการเชื่อมต่อขาเข้า (เช่นมาสเตอร์ของคุณที่นี่) จะต้องเป็นผู้ฟังและผูกเข้ากับพอร์ต หากไม่ได้ระบุพอร์ตสำหรับซ็อกเก็ตก่อนที่จะใช้ระบบปฏิบัติการจะกำหนดพอร์ตที่ใช้งานได้ให้กับซ็อกเก็ต เมื่อเจ้านายต้องการตอบสนองต่อทาสที่ส่งข้อมูลที่อยู่ของผู้ส่งจะสามารถเข้าถึงได้เมื่อผู้ฟังได้รับข้อมูล

ฉันคิดว่าคุณจะใช้ UDP สำหรับสิ่งนี้


0

หากคุณต้องการค้นหาพอร์ตว่างสำหรับใช้ในภายหลังนี่เป็นตัวอย่างข้อมูลที่คล้ายกับคำตอบก่อนหน้าแต่สั้นกว่าโดยใช้socketserver :

import socketserver

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

โปรดทราบว่าพอร์ตไม่ได้รับประกันว่าจะยังคงว่างอยู่ดังนั้นคุณอาจต้องวางข้อมูลโค้ดนี้และรหัสที่ใช้ในการวนซ้ำ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.