সকেট: জাভা ব্যবহার করে বন্দর উপলভ্যতা আবিষ্কার করুন


123

আমি কীভাবে জাভা ব্যবহার করে কোনও প্রদত্ত মেশিনে একটি বন্দরের উপলব্ধতা প্রোগ্রামক্রমে নির্ধারণ করতে পারি?

অর্থাত্ একটি বন্দর নম্বর দেওয়া হয়েছে, এটি ইতিমধ্যে ব্যবহৃত হচ্ছে কিনা তা নির্ধারণ করুন।


2
এই প্রশ্নটি কীভাবে জানাতে হবে যে প্রদত্ত বন্দরটি ইতিমধ্যে ব্যবহৃত হয়েছে কিনা, আপনি এখানে একটি অবৈতনিক বন্দর নম্বর পাওয়ার উপায় খুঁজতে চেষ্টা করে এখানে অবতরণ করতে পারেন, যা স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 2675362/… (আমার বক্তব্যটির লিঙ্ক সহ) .github.com / 3429822 ) আরও ভাল কভার করে।
ভর্বার্গার

কোন উদ্দেশ্যে? আপনি যদি শোনার জন্য খালি খালি সন্ধান করতে চান তবে শূন্যটি নির্দিষ্ট করুন। যেকোন স্ক্যানিং কৌশল সময়-উইন্ডো সমস্যার জন্য দায়বদ্ধ: আপনি যখন দাবি করতে যান তখন স্ক্যান করা এবং দখল করা বন্দরটি খালি থাকতে পারে
লার্নের মারকুইস

উত্তর:


91

এটি অ্যাপাচি উট প্রকল্প থেকে বাস্তবায়ন আসছে :

/**
 * Checks to see if a specific port is available.
 *
 * @param port the port to check for availability
 */
public static boolean available(int port) {
    if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) {
        throw new IllegalArgumentException("Invalid start port: " + port);
    }

    ServerSocket ss = null;
    DatagramSocket ds = null;
    try {
        ss = new ServerSocket(port);
        ss.setReuseAddress(true);
        ds = new DatagramSocket(port);
        ds.setReuseAddress(true);
        return true;
    } catch (IOException e) {
    } finally {
        if (ds != null) {
            ds.close();
        }

        if (ss != null) {
            try {
                ss.close();
            } catch (IOException e) {
                /* should not be thrown */
            }
        }
    }

    return false;
}

তারা ইউটিপি এবং টিসিপিতে বন্দরটি উপলভ্য কিনা তা পরীক্ষা করতে তারা ডেটাগ্রামস্কটটিও পরীক্ষা করে দেখছেন।

আশাকরি এটা সাহায্য করবে.


5
এটির একটি দুর্দান্ত বৈকল্পিক আপনার যদি মিনা থাকে উপলভ্য পোর্টফাইন্ডার getগনেক্সটভ্যাবিলিভাল (1024) যা আপনাকে পরবর্তী অন-সুবিধাযুক্ত বন্দর দেয়।
আলাইন ও'ডিয়া

9
এটি অবশ্য সব কিছু ধরেনা। উপরের রুটিন রিপোর্ট হিসাবে 8000 উপলব্ধ হিসাবে আমি টিসিপি 8000 উপর একটি চলমান nginx দ্বারা কামড়েছি। কোনও ধারণা নেই কেন - আমার সন্দেহ হয় যে এনগিনেক্স কিছু চটজলদি জিনিস করে (এটি ওএস এক্সে রয়েছে)। আমার পক্ষে কার্যকরী হ'ল উপরেরটি করা এবং একটি নতুন সকেট ("লোকালহোস্ট", বন্দর) খোলার পরে যদি আমরা কোনও ব্যতিক্রম না পাই তবে মিথ্যা ফিরিয়ে আনতে হবে। থটস?
আংশিক মেঘলা

2
উইন্ডোজে একই সমস্যা পেপারকুট এসএমটিপি সার্ভার চালু কিনা তা সনাক্ত করার চেষ্টা করছে। একটি সমাধান যেখানে আপনি কোনও বন্দরের সাথে সংযোগ স্থাপনের পরিবর্তে এটির সাথে বেঁধে দেওয়ার চেষ্টা করার পরিবর্তে (আংশিক ক্লোডিস মন্তব্য এবং ইভানের উত্তরের পরামর্শ অনুসারে) আরও নির্ভরযোগ্য কাজ করে বলে মনে হচ্ছে।
স্ট্যান করুন

4
মজাদার. সকেট ইতিমধ্যে আবদ্ধ হওয়ার পরে সেটরউজএড্রেস () এ কল করা সম্পূর্ণ অর্থহীন এবং এটি কোডের উদ্দেশ্যগুলির সাথে সম্পূর্ণ বিপরীত।
লার্নের মারকুইস

3
এই কোডটি সময়-উইন্ডো সমস্যার সাপেক্ষে। উদ্দেশ্য যদি ServerSocketকোনও বন্দর শোনানো তৈরি করা হয় তবে এটি করা উচিত এবং এটিটি ফিরিয়ে দিন ServerSocket। এটি তৈরি করে এবং তারপরে এটি বন্ধ করে এবং এটি ফিরিয়ে দেওয়া শূন্য গ্যারান্টি দেয় যে পরবর্তীতে ServerSocketসেই বন্দরটি ব্যবহার করে তৈরি করা যেতে পারে। Ditto for DatagramSocket
মারকুইস লরেনের

41

জাভা 7 এর জন্য আপনি আরও কমপ্যাক্ট কোডের জন্য ট্রাই-উইথ রিসোর্স ব্যবহার করতে পারেন:

private static boolean available(int port) {
    try (Socket ignored = new Socket("localhost", port)) {
        return false;
    } catch (IOException ignored) {
        return true;
    }
}

15
এটি বন্দরে পাওয়া যায় কিনা তা পরীক্ষা করে না। এটি তালিকাভুক্ত রাজ্যে রয়েছে কিনা, আইপি ঠিকানাটি পৌঁছনযোগ্য কিনা তা পরীক্ষা করে
লার্নের মারকুইস

1
অতিরিক্তভাবে এই পরীক্ষাটি বেশ ধীর (প্রতি বন্দরে প্রায় এক সেকেন্ড)।
জেম্যাক্স

আইওএক্সেপশন ধরা পড়লে কি এটি মিথ্যা ফিরানো উচিত নয়?
বারৌদি সাফওয়েন

@ বারোদিস্যাফওয়েন এটি ব্যতিক্রম আসলে কী তার উপর সম্পূর্ণ নির্ভর করে। জন্য ConnectException: 'connection refused', হ্যাঁ এটি মিথ্যা ফিরে উচিত। টাইমআউটগুলির জন্য, এটি ফেরত দিতে পারে এমন কোনও কিছুই বৈধ হবে না, কারণ আসল উত্তরটি জানা যায়নি। এজন্য এই কৌশলটি এই উদ্দেশ্যে অকেজো।
লার্নের মারকুইস

36

এটি জাভা 7 হিসাবে দেখা যায়, ডেভিড সান্তামারিয়া এর উত্তর আর নির্ভরযোগ্যভাবে কাজ করে না। দেখে মনে হচ্ছে আপনি সংযোগটি পরীক্ষা করতে এখনও নির্ভরযোগ্যভাবে সকেট ব্যবহার করতে পারেন।

private static boolean available(int port) {
    System.out.println("--------------Testing port " + port);
    Socket s = null;
    try {
        s = new Socket("localhost", port);

        // If the code makes it this far without an exception it means
        // something is using the port and has responded.
        System.out.println("--------------Port " + port + " is not available");
        return false;
    } catch (IOException e) {
        System.out.println("--------------Port " + port + " is available");
        return true;
    } finally {
        if( s != null){
            try {
                s.close();
            } catch (IOException e) {
                throw new RuntimeException("You should handle this error." , e);
            }
        }
    }
}

আমি তার পক্ষ থেকে কল করার জন্য কোনও প্রক্সি সার্ভার উপলব্ধ কিনা তা দেখতে চাই।
দেজেল

1
@ ডেভিডসন্তামারিয়ার উত্তর কখনই কার্যকর হয়নি। জাভা 7. এর সাথে কিছুই করার নেই
মারকুইস লরেনের

35

আপনি যদি পারফরম্যান্স নিয়ে খুব উদ্বিগ্ন না হন তবে আপনি সর্বদা সার্ভারসকেট ক্লাস ব্যবহার করে কোনও বন্দরে শোনার চেষ্টা করতে পারেন । যদি এটি ব্যতিক্রমী প্রতিক্রিয়া ফেলে তবে এটি ব্যবহার করা হচ্ছে।

public static boolean isAvailable(int portNr) {
  boolean portFree;
  try (var ignored = new ServerSocket(portNr)) {
      portFree = true;
  } catch (IOException e) {
      portFree = false;
  }
  return portFree;
}

সম্পাদনা: আপনি যা করার চেষ্টা করছেন সমস্ত যদি একটি মুক্ত বন্দর নির্বাচন করে থাকে তবে আপনার জন্য একটি new ServerSocket(0)খুঁজে পাবেন।


পরিস্কার করার জন্য অবশেষে ব্যবহার করুন (চেষ্টা করুন {...} ধরা {...} অবশেষে {যদি (সকেট! = নাল) সকেট.কোলোস ();
Hos

আপনি "পোর্টটেকেন = (সকেট == নাল)" সেট করতে পারেন; পরিবর্তে এটি ক্যাচ করার পরিবর্তে।
হোসাম অলি

1
আমি লেখকের প্রশ্নের অভিব্যক্তির মধ্যে পড়েছি বলে মনে করি না।
স্পেনসার রুপোর্ট

1
চেষ্টা / ধরা ছাড়াই এটি করার কোনও উপায় আছে কি? আমার উদ্দেশ্যে কোনও উপলভ্য বন্দর ব্যবহার করতে আমি আপত্তি করবো না , তবে পোর্ট সংখ্যার উপরে পুনরাবৃত্তি করব এবং যতক্ষণ না আমি একটি নিখরচায় কিছুটা অপ্রয়োজনীয় না খুঁজে পাওয়া যায় ততক্ষণ প্রতিটিটির উপর দিয়ে / ধরার চেষ্টা করি। কোথাও একটি 'নেটিভ বুলিয়ান উপলব্ধ (অন্তর্নিহিত)' পদ্ধতি নেই, যা কেবল পরীক্ষা করে?
ওরেেন শ্যালোভ

27
নতুন সেভারসকেট (0) স্বয়ংক্রিয়ভাবে একটি নিখর পোর্ট নির্বাচন করবে।
স্পেন্সার রুপোর্ট

10

নিম্নোক্ত সমাধানটি স্প্রিং-কোর (অ্যাপাচি লাইসেন্স) এর সকেট ইউটিলস বাস্তবায়নে অনুপ্রাণিত ।

Socket(...)এটি ব্যবহার করে অন্যান্য সমাধানের তুলনায় বেশ দ্রুত (1000 টিসিপি পোর্ট এক সেকেন্ডেরও কম সময়ে পরীক্ষা করা):

public static boolean isTcpPortAvailable(int port) {
    try (ServerSocket serverSocket = new ServerSocket()) {
        // setReuseAddress(false) is required only on OSX, 
        // otherwise the code will not work correctly on that platform          
        serverSocket.setReuseAddress(false);
        serverSocket.bind(new InetSocketAddress(InetAddress.getByName("localhost"), port), 1);
        return true;
    } catch (Exception ex) {
        return false;
    }
}       

3

সকেট ভিত্তিক সমাধানগুলি চেষ্টা করুন, সঠিক ফলাফল নাও পেতে পারে (সকেটের ঠিকানাটি "লোকালহোস্ট" এবং কিছু ক্ষেত্রে বন্দরটি "লুপব্যাক ইন্টারফেস" দ্বারা নয় "দখল করা" হতে পারে এবং উইন্ডোজে কমপক্ষে আমি দেখেছি এই পরীক্ষাটি ব্যর্থ হয়েছে অর্থাৎ প্রোটটি মিথ্যা হিসাবে উপলব্ধ হিসাবে ঘোষণা করা হয়েছে)।

সিআইসি নামে একটি দুর্দান্ত লাইব্রেরি রয়েছে , নিম্নলিখিত কোডটি আপনাকে আপ করতে পারে:

Sigar sigar = new Sigar();
int flags = NetFlags.CONN_TCP | NetFlags.CONN_SERVER | NetFlags.CONN_CLIENT;             NetConnection[] netConnectionList = sigar.getNetConnectionList(flags);
for (NetConnection netConnection : netConnectionList) {
   if ( netConnection.getLocalPort() == port )
        return false;
}
return true;

আমি পেয়েছি: "java.library.path এ সিগার-x86-winnt.dll" দুর্ভাগ্যক্রমে এটির জন্য এমন কিছু অতিরিক্ত dll ডাউনলোডের প্রয়োজন যা এন্টারপ্রাইজ পরিবেশে সত্যিকারভাবে টেকসই নয় (সিআই সিস্টেমের উপরে আমার কোনও নিয়ন্ত্রণ নেই)। খুব খারাপ .... যাইহোক ধন্যবাদ।
uthomas

@ বুথোমাস আমি অনুমান করি যে আপনার অ্যাপ প্রয়োগের প্যাকেজটিতে আপনার এখনও নিয়ন্ত্রণ রয়েছে, যদি আপনি এই অবস্থায় থাকেন তবে আপনার জার্সের কাছে সিগার নেটিভ রানটাইম ডিএলএল / এসও সরবরাহ করতে পারেন এবং জাভা লিব পাথকে ব্যবহারিকভাবে সেট করতে পারেন (সাধারণ হ্যাকের মাধ্যমে আপনি এটির পরেও প্রভাব ফেলতে পারেন আপনার অ্যাপটি জেভিএম চালু করেছে)।
শিলিল দ্য ক্যাট

2

ডেভিড সান্তামারিয়া দ্বারা চিহ্নিত উত্তরের একটি সাফাই:

/**
 * Check to see if a port is available.
 *
 * @param port
 *            the port to check for availability.
 */
public static boolean isPortAvailable(int port) {
    try (var ss = new ServerSocket(port); var ds = new DatagramSocket(port)) {
        return true;
    } catch (IOException e) {
        return false;
    }
}

এই এখনও একটি জাতি শর্ত ডেভিড Santamaria এর উত্তর মন্তব্যে user207421 দ্বারা নির্দিষ্ট সাপেক্ষে (কিছু পোর্ট দখল পারে পরে এই পদ্ধতি বন্ধ হয়ে যায় ServerSocketএবং DatagramSocketএবং আয়)।


1

আমার ক্ষেত্রে এটি বন্দরে সংযোগ স্থাপনে চেষ্টা করতে সহায়তা করেছে - যদি পরিষেবা ইতিমধ্যে উপস্থিত থাকে তবে এটি প্রতিক্রিয়া জানায়।

    try {
        log.debug("{}: Checking if port open by trying to connect as a client", portNumber);
        Socket sock = new Socket("localhost", portNumber);          
        sock.close();
        log.debug("{}: Someone responding on port - seems not open", portNumber);
        return false;
    } catch (Exception e) {         
        if (e.getMessage().contains("refused")) {
            return true;
    }
        log.error("Troubles checking if port is open", e);
        throw new RuntimeException(e);              
    }

1
যা চেয়েছিল তা নয়।
লার্নের মারকুইস

0

আমার ক্ষেত্রে আমাকে ডেটাগ্রামসকেট ক্লাস ব্যবহার করতে হয়েছিল।

boolean isPortOccupied(int port) {
    DatagramSocket sock = null;
    try {
        sock = new DatagramSocket(port);
        sock.close();
        return false;
    } catch (BindException ignored) {
        return true;
    } catch (SocketException ex) {
        System.out.println(ex);
        return true;
    }
}

প্রথমে আমদানি করতে ভুলবেন না

import java.net.DatagramSocket;
import java.net.BindException;
import java.net.SocketException;

এটি ইউডিপি বন্দরগুলির জন্য কাজ করে। প্রশ্নটি টিসিপি বন্দরগুলি সম্পর্কে বলে মনে হচ্ছে।
লার্নের মারকুইস

-2

আমি এর মতো কিছু চেষ্টা করেছি এবং এটি আমার সাথে সত্যই কার্যকর হয়েছিল

            Socket Skt;
            String host = "localhost";
            int i = 8983; // port no.

                 try {
                    System.out.println("Looking for "+ i);
                    Skt = new Socket(host, i);
                    System.out.println("There is a Server on port "
                    + i + " of " + host);
                 }
                 catch (UnknownHostException e) {
                    System.out.println("Exception occured"+ e);

                 }
                 catch (IOException e) {
                     System.out.println("port is not used");

                 }

1
যা চেয়েছিল তা নয়।
মারকুইস অফ লরেন

এবং একটি সকেট ফাঁস।
লার্নের মারকুইস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.