سؤال

أحتاج إلى طريقة سريعة لمعرفة ما إذا كان منفذ معين مفتوحًا مع روبي.أنا حاليا أعبث بهذا:

require 'socket'

def is_port_open?(ip, port)
  begin
    TCPSocket.new(ip, port)
  rescue Errno::ECONNREFUSED
    return false
  end
  return true
end

إنه يعمل بشكل رائع إذا كان المنفذ مفتوحًا، ولكن الجانب السلبي لذلك هو أنه في بعض الأحيان سيجلس وينتظر لمدة 10-20 ثانية ثم ينتهي الوقت في النهاية، ويرمي ETIMEOUT استثناء (إذا كان المنفذ مغلقا).سؤالي هو بالتالي:

هل يمكن تعديل هذا الرمز للانتظار لمدة ثانية فقط (والعودة false إذا لم نحصل على أي شيء بحلول ذلك الوقت) أم أن هناك طريقة أفضل للتحقق مما إذا كان منفذ معين مفتوحًا على مضيف معين؟

يحرر: يعد استدعاء رمز bash مقبولًا أيضًا طالما أنه يعمل عبر الأنظمة الأساسية (على سبيل المثال، Mac OS X و*nix وCygwin)، على الرغم من أنني أفضل رمز Ruby.

هل كانت مفيدة؟

المحلول

قد يعمل شيء مثل ما يلي:

require 'socket'
require 'timeout'

def is_port_open?(ip, port)
  begin
    Timeout::timeout(1) do
      begin
        s = TCPSocket.new(ip, port)
        s.close
        return true
      rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
        return false
      end
    end
  rescue Timeout::Error
  end

  return false
end

نصائح أخرى

المزيد من بناء الجملة الاصطلاحية لروبي:

require 'socket'
require 'timeout'

def port_open?(ip, port, seconds=1)
  Timeout::timeout(seconds) do
    begin
      TCPSocket.new(ip, port).close
      true
    rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
      false
    end
  end
rescue Timeout::Error
  false
end

جميع الإجابات الأخرى الموجودة غير مرغوب فيها.استخدام Timeout يكون محبط.ربما تعتمد الأمور على إصدار روبي.على الأقل منذ 2.0 يمكن للمرء ببساطة استخدام:

Socket.tcp("www.ruby-lang.org", 10567, connect_timeout: 5) {}

بالنسبة للروبي الأقدم، فإن أفضل طريقة يمكن أن أجدها هي استخدام وضع عدم الحظر وبعد ذلك select.الموصوفة هنا:

لقد توصلت مؤخرًا إلى هذا الحل باستخدام نظام يونكس lsof يأمر:

def port_open?(port)
  !system("lsof -i:#{port}", out: '/dev/null')
end

فقط من أجل الاكتمال، سيكون Bash شيئًا مثل هذا:

$ netcat $HOST $PORT -w 1 -q 0 </dev/null && do_something

-w 1 يحدد مهلة 1 ثانية، و -q 0 يقول أنه عند الاتصال، قم بإغلاق الاتصال في أقرب وقت stdin يعطي EOF (أيّ /dev/null سوف تفعل على الفور).

يحتوي Bash أيضًا على خدمات TCP/UDP المضمنة الخاصة به، لكنها خيار وقت الترجمة وليس لدي Bash مجمعة معها :P

جميع منصات *nix:

جرب الأمر nc/netcat كما يلي.

`nc -z -w #{timeout_in_seconds} -G #{timeout_in_seconds} #{host} #{port}`
if $?.exitstatus == 0
  #port is open
else
  #refused, port is closed
end

يمكن استخدام العلامة -z لإخبار nc بالإبلاغ عن المنافذ المفتوحة، بدلاً من بدء الاتصال.

تعني العلامة -w مهلة الاتصال وقراءات الشبكة النهائية

تشير العلامة -G إلى انتهاء مهلة الاتصال بالثواني

استخدم علامة -n للعمل مع عنوان IP بدلاً من اسم المضيف.

أمثلة:

# `nc -z -w 1 -G 1 google.com 80`
# `nc -z -w 1 -G 1 -n 123.234.1.18 80`

اختلافي الطفيف في إجابة كريس رايس.لا يزال يتعامل مع المهلة في محاولة واحدة ولكنه يسمح أيضًا بمحاولات متعددة حتى تستسلم.

    def is_port_open?(host, port, timeout, sleep_period)
      begin
        Timeout::timeout(timeout) do
          begin
            s = TCPSocket.new(host, port)
            s.close
            return true
          rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
            sleep(sleep_period)
            retry
          end
        end
      rescue Timeout::Error
        return false
      end
    end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top