Я работаю над следующей задачей, чтобы выяснить информацию о сертификате домена по URL, используя библиотеки сокетов OpenSSL, TCPSocket и TCP. В настоящее время я пытаюсь улучшить существующий процесс, используя библиотеку потоков для подключения к сокету и возврата информации. По большей части код, кажется, работает только с точки зрения скорости. Однако я получаю неточные результаты и не знаю, почему. Я не очень хорошо разбираюсь с потоками, TCPSockets или OpenSSL и, кроме того, я думаю, что сочетание этих библиотек / классов способствует этим ошибкам. Вот код, который у меня есть.
Код ниже - это класс, который я использую для проверки связи с URL-адресом и получения информации о его сертификате.
class SslClient
attr_reader :url, :port, :timeout
def initialize(url, port = '443', timeout = 10)
@url = url
@port = port
@timeout = timeout
end
def ping_for_certificate_info
context = OpenSSL::SSL::SSLContext.new
certificates = nil
verify_result = nil
Timeout.timeout(timeout) do
tcp_client = TCPSocket.new(url, port)
ssl_client = OpenSSL::SSL::SSLSocket.new tcp_client, context
ssl_client.hostname = url
ssl_client.sync_close = true
ssl_client.connect
certificates = ssl_client.peer_cert_chain_with_openssl_extension
verify_result = ssl_client.verify_result
tcp_client.close
end
{certificate: certificates.first, verify_result: verify_result }
rescue => error
puts error.inspect
end
end
Код ниже является сокращенным версия того, как мой код использует SslClient для записи информации:
domains.map do |url|
Thread.new do
ssl_client = SslClient.new(struct.domain.gsub("*.", "www."), url.scan_port)
cert_info = ssl_client.ping_for_certificate_info
if cert_info
#### Does some if logic for the cert ######
else
###### Does some else logic for the cert, etc. ######
end
end
end.map(&:value)
#### Do more stuff ######
Когда я запускаю код как есть, я получаю следующую ошибку:
#<Timeout::Error: execution expired>
Если я увеличу аргумент времени ожидания через SslCient
до чего-то смешного, например 30 секунд, я получаю следующую ошибку: #<SocketError: getaddrinfo: Temporary failure in name resolution>
Если бы я получил список 20 лучших веб-сайтов и запустил код с тайм-аутом, установленным на 30, только несколько доменов будут возвращать SocketError, и он варьируется от 3 ошибок сокетов до примерно 8. Однако в более ранней и более медленной версии без многопоточности вся информация о домене проверяется в чистоте и точности. Я не уверен, почему это так.
Возможно ли, что Нить как-то связана с этой проблемой? Или, может быть, я закрываю связь «чтобы быстро»? Я пытался исследовать код по частям, и я подозреваю, что поток является проблемой. Однако я не уверен в том, почему это может быть проблемой из-за того, что я прочитал, что потоки являются стандартными для работы API / внешних вызовов. Кто-нибудь есть рекомендации, которые я мог бы попытаться решить эту проблему? Спасибо.