उपलब्ध पोर्ट कैसे खोजें?


194

मैं एक सर्वर शुरू करना चाहता हूं जो एक पोर्ट को सुनता है। मैं स्पष्ट रूप से पोर्ट निर्दिष्ट कर सकता हूं और यह काम करता है। लेकिन मैं एक पोर्ट को स्वचालित तरीके से खोजना चाहूंगा। इस संबंध में मेरे दो सवाल हैं।

  1. पोर्ट नंबर की किस श्रेणी में मुझे खोज करनी चाहिए? (मैंने पोर्ट 12345, 12346 और 12347 का उपयोग किया और यह ठीक था)।

  2. यदि किसी दिए गए पोर्ट पर किसी अन्य सॉफ़्टवेयर का कब्जा नहीं है, तो मुझे कैसे पता चलेगा?

जवाबों:


277

यदि आप उपयोग किए जाने वाले पोर्ट को बुरा नहीं मानते हैं, तो ServerSocket कंस्ट्रक्टर को 0 का पोर्ट निर्दिष्ट करें और यह किसी भी मुक्त पोर्ट पर सुनेगा।

ServerSocket s = new ServerSocket(0);
System.out.println("listening on port: " + s.getLocalPort());

यदि आप बंदरगाहों के एक विशिष्ट सेट का उपयोग करना चाहते हैं, तो सबसे आसान तरीका संभवतः उनके माध्यम से चलना है जब तक कि एक काम नहीं करता। कुछ इस तरह:

public ServerSocket create(int[] ports) throws IOException {
    for (int port : ports) {
        try {
            return new ServerSocket(port);
        } catch (IOException ex) {
            continue; // try next port
        }
    }

    // if the program gets here, no port in the range was found
    throw new IOException("no free port found");
}

इस तरह इस्तेमाल किया जा सकता है:

try {
    ServerSocket s = create(new int[] { 3843, 4584, 4843 });
    System.out.println("listening on port: " + s.getLocalPort());
} catch (IOException ex) {
    System.err.println("no available ports");
}

2
नए सर्वर सॉकेट (0) का उपयोग करते समय, इसे बंद करने के लिए देखभाल की जानी चाहिए! Javasourcecode.org/html/open-source/eclipse/eclipse-3.5.2/org/… के आधार पर , मेरे gist.github.com/3429822
vorburger

9
@ थ्योरीबर्गर, उस तरीके से कर रहा है, जो दौड़ की स्थिति से ग्रस्त है। यह केवल सर्वर सॉकेट पर तुरंत सुनने के लिए अच्छा है, बजाय इसे खोलने के लिए एक मुफ्त बंदरगाह खोजने के लिए, इसे फिर से बंद करें, और फिर एक मुक्त बंदरगाह पर फिर से खोलें (जिस समय तक एक छोटा सा मौका होता है कुछ और अब उस पर सुन रहा है port।)
ग्राहम एडगकोम्बे

7
सहमत, लेकिन यह सटीक उपयोग के मामले पर निर्भर करता है: मेरे मामले में मुझे इसे कुछ एपीआई में (एक एम्बेडेड जेट्टी स्टार्टर, परीक्षणों के लिए) कहने के लिए एक मुफ्त पोर्ट नंबर खोजने की आवश्यकता थी - संबंधित एपीआई एक सॉकेट नंबर चाहता है - पहले से ही नहीं सर्वर सॉकेट खोला। तो यह निर्भर करता है।
वोरबर्गर

4
@vorburger उचित API शून्य को सुनने के लिए एक वैध पोर्ट संख्या के रूप में स्वीकार करेगा, और फिर आपको वास्तविक पोर्ट को सुनने के लिए बताएगा। होवेवर, कई उचित एपीआई नहीं हैं: कई कार्यक्रमों में विशेष रूप से 0 पोर्ट के लिए परीक्षण किया जाता है और इसे मना कर दिया जाता है ( ssh -D 127.0.0.0:0 ...! नहीं!), जो वास्तव में निराशाजनक है। हमें उन्हें उपयोग करने के लिए बहुत सारे पुस्तकालयों / कार्यक्रमों को पैच करना पड़ा।
जोकर_vD

2
@vorburger किसी भी पोर्ट का उपयोग करते समय , इसे बंद करने के लिए देखभाल की जानी चाहिए। new ServerSocket(0)इस संबंध में अलग नहीं है। इस बारे में आपकी पहली कड़ी में कुछ भी नहीं है। आपका दूसरा लिंक केवल खराब अभ्यास को प्रदर्शित करता है। एक बार निर्माण करने के बाद ServerSocketआपको इसका उपयोग करना चाहिए , इसे बंद नहीं करना चाहिए और उसी पोर्ट नंबर का पुन: उपयोग करने का प्रयास करना चाहिए । वह सब समय की पूरी बर्बादी है, साथ ही समय-खिड़की की समस्याओं की चपेट में है।
लोर्ने

57

यदि आप ServerSocket के निर्माता को पोर्ट नंबर के रूप में 0 पास करते हैं, तो यह आपके लिए एक पोर्ट आवंटित करेगा।


हां, मुझे लगता है कि यह सबसे सुरुचिपूर्ण समाधान है लेकिन कुछ कारणों से यह मेरे मामले में काम नहीं करता है। लेकिन मुझे अभी भी यह पता लगाना है कि वास्तव में क्या गलत है।
रोमन

1
@ रोमान: यह काम क्यों नहीं करता है? इसे शामिल करने के लिए अपने प्रश्न को अपडेट करें (या लोग इसे सुझाते रहेंगे) और बताएं कि यह समाधान आपके लिए क्यों विफल है।
FrustratedWithFormsDesigner

2
क्लाइंट से मुझे यह पोर्ट कैसे मिलेगा? ;)
ईडी २२

34

जावा 1.7 से शुरू आप इस तरह की कोशिश के साथ संसाधनों का उपयोग कर सकते हैं:

  private Integer findRandomOpenPortOnAllLocalInterfaces() throws IOException {
    try (
        ServerSocket socket = new ServerSocket(0);
    ) {
      return socket.getLocalPort();

    }
  }

यदि आपको वैकल्पिक कंस्ट्रक्टरों के लिए एक विशिष्ट इंटरफ़ेस चेक सर्वरस्केट डॉक्यूमेंट पर एक खुला पोर्ट खोजने की आवश्यकता है ।

चेतावनी: इस पद्धति द्वारा लौटाए गए पोर्ट नंबर का उपयोग करने वाला कोई भी कोड एक दौड़ की स्थिति के अधीन होता है - एक अलग प्रक्रिया / थ्रेड सर्वर पोर्ट के बंद होने के तुरंत बाद हम उसी पोर्ट से जुड़ सकते हैं।


1
यदि आप सेट नहीं करते हैं तो यह काम नहीं कर सकता है SO_REUSEADDR। और एक दौड़ की स्थिति है, लेकिन इसे ठीक करना मुश्किल है।
डेविड एहरमन

यदि आप बाद में उसी पोर्ट नंबर के साथ एक और खोलने की कोशिश करते हैं तो यह काम नहीं ServerSocketकर सकता है, क्योंकि यह इस बीच लिया जा सकता है। आप ServerSocketइसे बंद करने के बजाय केवल वास्तविक क्यों नहीं लौटाएंगे यह एक रहस्य बना हुआ है।
लोर्ने

5
@ ईजेपी कभी-कभी थर्ड पार्टी कोड पोर्ट को स्वीकार करता है लेकिन सॉकेट को ही नहीं।
कैप्टन मैन

@ कैप्टनमैन ज़रूर, लेकिन उन मामलों में पोर्ट को निश्चित रूप से प्रचारित माना जाता है। डायनामिक रूप से आवंटित पोर्ट को कुछ अन्य तंत्रों जैसे नामकरण सेवा या प्रसारण या mulitcast द्वारा ग्राहकों को आपूर्ति की जानी है। यहां पूरा प्रश्न विकृत है।
लोर्ने

@ user207421 आप पोर्ट के ServerSocketबदले के बजाय स्वीकार करने के लिए थर्ड पार्टी कोड नहीं बदल सकते int
कप्तान मैन

30

विकिपीडिया के अनुसार , आपको बंदरगाहों 49152का उपयोग करना चाहिए65535 यदि आपको 'सुप्रसिद्ध' पोर्ट की आवश्यकता नहीं है, तो आपको ।

AFAIK एक बंदरगाह का निर्धारण करने का एकमात्र तरीका उपयोग में है इसे खोलने का प्रयास करना।


6
+1। चूंकि विकिपीडिया हमेशा पूर्ण सत्य / तथ्यों का स्रोत नहीं है, मैंने सोचा कि यह नोट करना उपयोगी हो सकता है कि, विकिपीडिया पृष्ठ के लिए संदर्भ "इंटरनेट असाइन किए गए नंबर प्राधिकरण (IANA)" से आता है [सेवा का नाम और परिवहन प्रोटोकॉल पोर्ट नंबर रजिस्ट्री ( iana.org/assignments/service-names-port-numbers/… "पृष्ठ, RFC 6335 पर आधारित - धारा 6 (इस मामले में" ठोस "संदर्भ! :))।
ओजगुर

25

यदि आपको रेंज उपयोग की आवश्यकता है :

public int nextFreePort(int from, int to) {
    int port = randPort(from, to);
    while (true) {
        if (isLocalPortFree(port)) {
            return port;
        } else {
            port = ThreadLocalRandom.current().nextInt(from, to);
        }
    }
}

private boolean isLocalPortFree(int port) {
    try {
        new ServerSocket(port).close();
        return true;
    } catch (IOException e) {
        return false;
    }
}

सोच रहा था कि एक बंदरगाह की जांच कैसे की जाए, तो इससे unbind करें। धन्यवाद सर्गेई!
व्लादी इली

5
यदि रेंज का प्रत्येक पोर्ट [से, से) उपयोग में है, तो यह कोड अनंत रूप से लूप करेगा (या कम से कम जब तक कि उन पोर्ट में से कोई एक मुक्त नहीं हो जाता)। यदि आप यादृच्छिक पर सीमा में बंदरगाहों को चुनने के बजाय एक अनुक्रमिक स्कैन करते हैं, तो आप इस संभावना से बच सकते हैं (बस एक अपवाद को फेंक दें जब आप मुफ्त बंदरगाह को खोजने के बिना सीमा के अंत में पहुंचते हैं)। यदि आपको वास्तव में बंदरगाहों को यादृच्छिक रूप से चुनने की आवश्यकता है, तो आपको उन बंदरगाहों पर नज़र रखने के लिए एक सेट की आवश्यकता है जो आपने अब तक की कोशिश की है, और फिर उस सेट के आकार के बराबर होने पर एक त्रुटि उठाएं।
साइमन Kissane

पोर्ट 0 काफी सरल है और ServerSocketsसफलता के मामले में दो बनाने की आवश्यकता नहीं है , और इस कोड की टाइम-विंडो समस्याओं से ग्रस्त नहीं है।
लोर्ने

21

यदि आप स्प्रिंग का उपयोग करते हैं तो आप http://docs.spring.io/spring/docs/4.0.5.RELEASE/javadoc-api/org/springframework/util/SocketUtils/#findAvailableTcpPort-- आज़मा सकते हैं


उन लोगों के लिए जो उत्सुक हैं, हुड के तहत SpringUtils.findAvailableTcpPort()अन्य उत्तरों में बिल्कुल वही सिफारिश कर रहे हैं: एक बंदरगाह चुनें फिर प्रयास करें new ServerSocket(port)
अलेक्सई बेरेज़किन



6

यह मेरे लिए जावा 6 पर काम करता है

    ServerSocket serverSocket = new ServerSocket(0);
    System.out.println("listening on port " + serverSocket.getLocalPort());

6

मैंने हाल ही में परीक्षण के लिए एक छोटी सी लाइब्रेरी जारी की है जिसे ध्यान में रखते हुए। मावेन निर्भरता है:

<dependency>
    <groupId>me.alexpanov</groupId>
    <artifactId>free-port-finder</artifactId>
    <version>1.0</version>
</dependency>

एक बार स्थापित होने के बाद, मुफ्त पोर्ट नंबर प्राप्त किए जा सकते हैं:

int port = FreePortFinder.findFreeLocalPort();

4

यदि आपका सर्वर शुरू होता है, तो उस सॉकेट का उपयोग नहीं किया गया था।

संपादित करें

कुछ इस तरह:

ServerSocket s = null ;

try { 
    s = new ServerSocket( 0 ); 
} catch( IOException ioe ){
   for( int i = START; i < END ; i++ ) try {
        s = new ServerSocket( i );
    } catch( IOException ioe ){}
}
// At this point if s is null we are helpless
if( s == null ) {
    throw new IOException(
       Strings.format("Unable to open server in port range(%d-%d)",START,END));
}

पता नहीं किसने आपको वोट दिया, लेकिन मैंने आपको वापस वोट दिया। आप सर्वर सॉकेट को सेटअप करने का प्रयास करने के लिए एक पुनरावर्ती फ़ंक्शन सेट कर सकते हैं, और यदि आपको एक IOException (या जो कुछ भी है) मिलता है, तो आप तब तक फिर से प्रयास करते हैं जब तक कि यह सफलतापूर्वक पोर्ट न हो जाए।
jonescb

मुझे लगता है कि यह जाँचना बेहतर है कि क्या पोर्ट उपलब्ध है और फिर इस पोर्ट को सुनना शुरू करने का प्रयास करें। यह कुछ शुरू करने के लिए सुरुचिपूर्ण नहीं लगता है और तब पता चलता है कि कुछ समस्याएँ हैं और फिर इन समस्याओं को हल करने का प्रयास करें।
रोमन

2
@ अच्छी तरह से, हाँ, यह बेहतर होगा, इस तथ्य के अलावा कि पोर्ट उपलब्ध है या नहीं, यह जानने की कोई विधि नहीं है। यदि new ServerSocket(0)आपके विकल्प के लिए काम नहीं कर रहा है तो यह है। मुझे लगता है कि 85% संभावनाएं हैं जो आप मेरे सुझाव का उपयोग करते हुए समाप्त करते हैं।
OscarRyz

यह कोड ServerSocketsहमेशा के लिए खुलता और लीक होता रहता है और केवल वही अंतिम रहता है जो सफल रहा। यह एक breakबयान की जरूरत है ।
लोर्ने

4

यदि आप अपना स्वयं का सर्वर बनाना चाहते हैं ServerSocket, तो आप बस इसके लिए एक मुफ्त पोर्ट चुन सकते हैं:

  ServerSocket serverSocket = new ServerSocket(0);
  int port = serverSocket.getLocalPort();

अन्य सर्वर कार्यान्वयन में आमतौर पर समान समर्थन होता है। उदाहरण के लिए जेट्टी तब तक एक मुफ्त पोर्ट चुनती है जब तक आप इसे स्पष्ट रूप से सेट नहीं करते हैं:

  Server server = new Server();
  ServerConnector connector = new ServerConnector(server);
  // don't call: connector.setPort(port);
  server.addConnector(connector);
  server.start();
  int port = connector.getLocalPort();

3

यह आपकी बहुत मदद नहीं कर सकता है, लेकिन मेरी (उबंटू) मशीन पर मेरे पास एक फ़ाइल / आदि / सेवाएं हैं जिनमें कम से कम कुछ ऐप द्वारा उपयोग किए गए / आरक्षित पोर्ट दिए गए हैं। ये उन ऐप्स के लिए मानक पोर्ट हैं।

कोई गारंटी नहीं है कि ये चल रहे हैं, बस इन ऐप्स का उपयोग करने वाले डिफ़ॉल्ट पोर्ट (इसलिए यदि संभव हो तो आपको उनका उपयोग नहीं करना चाहिए)।

लगभग 500 से अधिक बंदरगाह परिभाषित हैं, लगभग आधा यूडीपी और आधा टीसीपी।

फ़ाइलें IANA द्वारा जानकारी का उपयोग करके बनाई गई हैं, IANA असाइन किए गए पोर्ट नंबर देखें


एक समान (और अधिक पूर्ण, IIRC) सूची है जो नैम्प के हिस्से के रूप में आती है। +1
rmeador

3

यदि आप स्प्रिंग का उपयोग कर रहे हैं, तो मिखाइल निकोलेव द्वारा प्रदान किया गया उत्तर सबसे सरल और साफ है, और आईएमओ को उखाड़ फेंकना चाहिए। बस सुविधा के उद्देश्य के लिए, मैं स्प्रिंगलाइनवर्क सॉकेट यूटिल्स .findAvailableTcpPort () विधि का उपयोग करके इनलाइन उदाहरण जोड़ूंगा :

int randomAvailablePort = SocketUtils.findAvailableTcpPort();

यह उतना ही आसान है, बस एक लाइन :)। बेशक, यूटिल्स वर्ग कई अन्य दिलचस्प तरीकों की पेशकश करता है, मेरा सुझाव है कि डॉक्स पर एक नज़र डालें।


1

'ServerSocket' क्लास का उपयोग करके हम यह पहचान सकते हैं कि दिया गया पोर्ट उपयोग में है या मुफ्त। ServerSocket एक कंस्ट्रक्टर प्रदान करता है जो पूर्णांक (जो पोर्ट नंबर है) को तर्क के रूप में लेता है और पोर्ट पर सर्वर सॉकेट को आरंभ करता है। यदि ServerSocket किसी IO अपवाद को फेंकता है, तो हम मान सकते हैं कि यह पोर्ट पहले से ही उपयोग में है।

निम्नलिखित स्निपेट का उपयोग सभी उपलब्ध बंदरगाहों को प्राप्त करने के लिए किया जाता है।

for (int port = 1; port < 65535; port++) {
         try {
                  ServerSocket socket = new ServerSocket(port);
                  socket.close();
                  availablePorts.add(port);
         } catch (IOException e) {

         }
}

संदर्भ लिंक


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.