Skip to content

Instantly share code, notes, and snippets.

@robuye
Created January 27, 2019 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robuye/847acaeff0c68b61fdd03fb5724bfee1 to your computer and use it in GitHub Desktop.
Save robuye/847acaeff0c68b61fdd03fb5724bfee1 to your computer and use it in GitHub Desktop.
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