Created
January 27, 2019 14:06
-
-
Save robuye/847acaeff0c68b61fdd03fb5724bfee1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'curb' | |
require 'socket' | |
URL = 'https://google.com' | |
# 0123456 default & reserved RubyVM. It will probably include 7 from Dir.glob | |
FDS_OPEN_BEFORE_START = Dir.glob("/proc/self/fd/*").map do |fd_path| | |
File.basename(fd_path).to_i | |
end | |
def run! | |
multi = Curl::Multi.new | |
5.times do |n| | |
easy = Curl::Easy.new(URL) do |curl| | |
curl.on_complete { puts "Transfer #{n+1} completed. Open FDs (#{open_fds.size}): #{open_fds.inspect}"; inspect_open_sockets } | |
end | |
multi.add(easy) | |
end | |
multi.max_connects = 1 | |
multi.perform | |
multi | |
end | |
def open_fds | |
fds = Dir.glob("/proc/self/fd/*").map do |fd_path| | |
File.basename(fd_path).to_i | |
end | |
(fds - FDS_OPEN_BEFORE_START).sort | |
end | |
def inspect_open_sockets | |
open_fds.each do |fd| | |
io = IO.for_fd(fd) rescue nil # discard on race condition | |
next unless io | |
stat = io.stat | |
next unless stat.ftype == "socket" || stat.ftype == "file" | |
link = case stat.ftype | |
when "socket" then get_socket_address_for_fd(fd) | |
when "file" then File.readlink("/proc/self/fd/#{fd}") | |
else "" | |
end | |
puts "FD #{fd}; #{stat.ftype}: #{link}" | |
end | |
end | |
def get_socket_address_for_fd(fd) | |
soc = BasicSocket.for_fd(fd) | |
from = "#{soc.connect_address.ip_address}:#{soc.connect_address.ip_port}" | |
to = "#{soc.remote_address.ip_address}:#{soc.remote_address.ip_port}" | |
"#{from} => #{to}" | |
end | |
puts "System FDs: #{FDS_OPEN_BEFORE_START.uniq.inspect}" | |
puts "These FDs will be ignored." | |
puts "Additional FDs open before start (#{open_fds.size}): #{open_fds.inspect}" | |
inspect_open_sockets | |
puts "Starting multi" | |
multi = run! | |
puts "All transfers completed" | |
puts "Open FDs after multi completed (#{open_fds.size}): #{open_fds.inspect}" | |
inspect_open_sockets | |
puts "Sleeping 10 seconds..." | |
10.times { sleep 1; print '.' } | |
puts | |
puts "Open FDs after sleep (#{open_fds.size}): #{open_fds.inspect}" | |
inspect_open_sockets | |
puts | |
puts "Add 5 new transfers" | |
puts | |
5.times do |n| | |
easy = Curl::Easy.new(URL) do |curl| | |
curl.on_complete { puts "Transfer #{n+1} completed. Open FDs (#{open_fds.size}): #{open_fds.inspect}"; inspect_open_sockets } | |
end | |
multi.add(easy) | |
end | |
puts "FDs open before start (#{open_fds.size}): #{open_fds.inspect}" | |
inspect_open_sockets | |
puts "Starting multi" | |
multi.perform | |
puts "All transfers completed" | |
puts "Open FDs after multi completed (#{open_fds.size}): #{open_fds.inspect}" | |
inspect_open_sockets | |
puts |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment