Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Some more adventure of Happy Eyeballs

Some more adventure of Happy Eyeballs

RubyKaigi 2024 follow up
https://rhc.connpass.com/event/320709/

More Decks by Misaki Shioi(塩井美咲/しおい)

Other Decks in Programming

Transcript

  1. QQTFMG ɹԘҪඒ࡙ ͓͍͠  ɹ!TIJPJNN (JU)VC  ɹ!DPF@ 5XJUUFS !DPF

    #MVFTLZ  3VCZ,BJHJͰ ʮ"OBEWFOUVSFPG)BQQZ&ZFCBMMTʯͱ͍͏ ൃදΛ͠·ͨ͠
  2. ͜Ε·Ͱͷ͋Β͢͡ঢ়ଶભҠͰ͋ΒΘ͢)&W WD GBJMVSF WX TVDDFTT WD WD TUBSU WX UJNFPVU

    )&Wͷಈ࡞ϑϩʔΛදݱ͢ΔԼهͷΑ͏ͳঢ়ଶભҠਤΛ࡞੒͠ ͜ΕΛϕʔεʹ4PDLFUUDQͷ)&W࣮૷Λߦͳͬͨ ʜ֤ঢ়ଶ ʜঢ়ଶͷભҠ
  3. ͜Ε·Ͱͷ͋Β͢͡)&Wͷঢ়ଶભҠ WD GBJMVSF WX TVDDFTT WD WD TUBSU WX UJNFPVU

    ઌʹ*1WΛղܾ ઌʹ*1WΛղܾ ʜݩͷঢ়ଶ ʜભҠઌͷঢ়ଶ TUBSU։࢝࣌఺Ͱͷঢ়ଶɻ*1Wͱ*1Wͷ໊લղܾΛಉ࣌ʹ։࢝͢Δ ͲͪΒ͔͕׬ྃ͢Δ·Ͱ଴ػ͢Δ
  4. ͜Ε·Ͱͷ͋Β͢͡)&Wͷঢ়ଶભҠ WD GBJMVSF WX TVDDFTT WD WD TUBSU WX UJNFPVU

    ࣌ؒ಺ʹ*1Wͷ໊લղܾ׬ྃͤͣ ࣌ؒ಺ʹ*1Wͷ໊લղܾ׬ྃ WX*1Wͷ໊લղܾΛNT଴ػ 3FTPMVUJPO%FMBZ
  5. ͜Ε·Ͱͷ͋Β͢͡)&Wͷঢ়ଶભҠ WD GBJMVSF WX TVDDFTT WD WD TUBSU WX UJNFPVU

    ˞͍ͣΕͷঢ়ଶ΋઀ଓ։࢝ޙ͸WX΁ભҠͯ͠઀ଓΛ଴ػ WD*1WΞυϨεѼʹ઀ଓ։࢝WD*1WΞυϨεѼʹ઀ଓ։࢝ WD*1WΞυϨε·ͨ͸*1WΞυϨεѼʹ઀ଓ։࢝
  6. ͜Ε·Ͱͷ͋Β͢͡)&Wͷঢ়ଶભҠ WD GBJMVSF WX TVDDFTT WD WD TUBSU WX UJNFPVU

    ଴ػͷϦτϥΠ ೋճ໨Ҏ߱ͷ઀ଓ։࢝Մೳ WX઀ଓͷ׬ྃ·ͨ͸໊લղܾͷ׬ྃΛNT଴ػ  $POOFDUJPO"UUFNQU%FMBZ ͢΂ͯͷ໊લղܾ͔઀ଓʹࣦഊ ϢʔβʔࢦఆͷλΠϜΞ΢τ͕ൃੜ ઀ଓʹ੒ޭ
  7. def self.tcp(host, port, ...) # ... state = :start loop

    do case state when :start then when :v4w then when :v6c, :v4c, :v46c then when :v46w then when :success then when :failure then when :timeout then end end end ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ શମ૾ ໊લղܾΛ։࢝͢Δ IPv6ͷ໊લղܾ׬ྃΛ50ms଴ػ͢Δ ઀ଓΛ։࢝͢Δ ઀ଓঢ়ଶͷ֬ఆͱ໊લղܾͷ׬ྃΛ଴ػ͢Δ ઀ଓʹ੒ޭͨ͠ιέοτΛฦ͢ ྫ֎Λൃੜͤ͞Δ λΠϜΞ΢τྫ֎Λൃੜͤ͞Δ ࣮૷ʹ͋ͨͬͯ͸,FSOFMMPPQͱDBTFΛ ૊Έ߹ΘͤΔ͜ͱͰઌ΄Ͳͷঢ়ଶભҠΛදݱ͢Δ
  8. def self.tcp(host, port, ...) # ... state = :start loop

    do case state when :start then when :v4w then when :v6c, :v4c, :v46c then when :v46w then when :success then when :failure then when :timeout then end end end ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ શମ૾ ໊લղܾΛ։࢝͢Δ IPv6ͷ໊લղܾ׬ྃΛ50ms଴ػ͢Δ ઀ଓΛ։࢝͢Δ ઀ଓঢ়ଶͷ֬ఆͱ໊લղܾͷ׬ྃΛ଴ػ͢Δ ઀ଓʹ੒ޭͨ͠ιέοτΛฦ͢ ྫ֎Λൃੜͤ͞Δ λΠϜΞ΢τྫ֎Λൃੜͤ͞Δ ϧʔϓ಺Ͱ͸ඞͣʮݱࡏͷঢ়ଶʯ͕ઃఆ͞Ε͍ͯΔɻ ঢ়ଶʹԠͯ͡ߦ͏΂͖ॲཧΛ࣮ߦ͠ɺ ࣍ͷঢ়ଶΛઃఆ͠ɺ࣍ͷϧʔϓʹਐΉ ֤ঢ়ଶͰߦ͏ॲཧ TUBUFʮݱࡏͷঢ়ଶʯΛ؅ཧ͢Δม਺ ॳظঢ়ଶͱͯ͠TUBSUΛઃఆ  ݱࡏͷঢ়ଶ
  9. case state when :start # ... h hostname_resolution_threads.concat( resolving_family_names.map {

    |family| thread_args = [family, *hostname_resolution_args] thread = Thread.new(*thread_args) { |*thread_args| hostname_resolution(*thread_args) } Thread.pass thread } ) # ... ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ TUBSU TUBSUΞυϨεϑΝϛϦ͝ͱʹεϨουΛੜ੒ɻ ͦΕͧΕͷࢠεϨουͰ໊લղܾ༻ͷϝιουΛ ݺͼग़͢͜ͱʹΑΓɺ*1W*1Wͷ໊લղܾΛ ฒߦʹ։࢝͢Δɻ hostname_resolution_args = [host, port, hostname_resolution_queue] ֤ࢠεϨουͰ໊લղܾϝιουΛ࣮ߦ ΞυϨεϑΝϛϦ͝ͱʹεϨουΛ࡞੒ ˞໊લղܾΛ։࢝͢ΔͨΊͷঢ়ଶ
  10. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next (hostname_resolution_waiting, nil, nil, remaining) ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ TUBSU TUBSU*0TFMFDUΛ༻໊͍ͯલղܾ͕׬ྃ͢Δ·Ͱ  جຊతʹ͸ ແظݶͰ଴ػ͢Δ ͲͪΒ͔ͷ໊લղܾ͕׬ྃ͢Δ·ͰॲཧΛϒϩοΫ ˞໊લղܾΛ։࢝͢ΔͨΊͷঢ়ଶ ϢʔβʔࢦఆͷλΠϜΞ΢τ஋ ࢦఆ͕ͳ͍৔߹͸OJMແظݶ ࣍ͷঢ়ଶΛܾఆ ࣍ͷঢ়ଶ΁ ໊લղܾͷ݁ՌΛऔಘ
  11. ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ WX case state when :v4w ipv6_resolved, _, = IO.select(

    if ipv6_resolved family_name, res = hostname_resolution_queue.get selectable_addrinfos.add(family_name, res) unless res.is_a? E state = :v46c else state = :v4c end next WX*0TFMFDUΛ༻͍ͯ*1Wͷ໊લղܾΛNT଴ػɻ ଴ػ࣌ؒ಺ʹ*1Wͷ໊લղܾ͕׬͔ྃͨ͠ʹΑͬͯɺ ࣍ͷঢ়ଶΛ൑அ͢Δɻ (hostname_resolution_waiting, nil, nil, RESOLUTION_DELAY) ˞ઌʹ*1WΛղܾͰ͖ͨ৔߹ʹ*1Wͷ໊લղܾΛ଴ػ͢ΔͨΊͷঢ়ଶ Exception NT ࣍ͷঢ়ଶ΁ ࣍ͷঢ়ଶΛܾఆ *1Wͷ໊લղܾ͕׬ྃ͢Δ͔λΠϜΞ΢τ͢Δ·ͰॲཧΛϒϩοΫ
  12. ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ WDWDWD case state when :v6c, :v4c, v46c # ...

    addrinfo = selectable_addrinfos.get # ... socket = Socket.new( # ... result = socket.connect_nonblock(addrinfo, exception: false) # ... connecting_sockets.add(socket, addrinfo) state = :v46w # ... next (addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) WDWDWDղܾࡁΈͷΞυϨεΛͻͱͭऔಘ͠ɺ ϊϯϒϩοΩϯάϞʔυͰ઀ଓΛ։࢝ɻ ઀ଓ͠ʹཁͨ͠ιέοτΛอଘͯ͠WX΁ભҠ ˞઀ଓΛ։࢝͢ΔͨΊͷঢ়ଶ औಘࡁΈͷΞυϨεΛҰͭऔಘ ઀ଓΛ։࢝ ࣍ͷঢ়ଶ΁ ࣍ͷঢ়ଶΛηοτ ઀ଓʹ࢖༻ͨ͠ιέοτΛอଘ
  13. ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ WX case state when :v46w # ... hostname_resolved, connectable_sockets,

    = IO.select( # ... if connectable_sockets&.any? # ... elsif hostname_resolved&.any? # ... else # ... end # ... next (hostname_resolution_waiting, connecting_sockets.all, nil, remaining) WX*0TFMFDUΛ༻͍ͯ઀ଓঢ়ଶͷ֬ఆ͔ ໊લղܾͷ׬ྃΛNT଴ػɻ*0TFMFDUͷ݁Ռ ൃੜͨ͠ΠϕϯτͳͲʹΑͬͯɺ࣍ͷঢ়ଶΛ൑அ͢Δ ˞઀ଓঢ়ଶͷ֬ఆͱ໊લղܾͷ׬ྃΛಉ࣌ʹ଴ػ͢ΔͨΊͷঢ়ଶ NT ࣍ͷঢ়ଶ΁ ࣍ͷঢ়ଶΛܾఆ  ઀ଓঢ়ଶ͕֬ఆ  ໊લղܾ͕׬ྃ $POOFDUJPO"UUFNQU%FMBZ͕λΠϜΞ΢τ ઀ଓঢ়ଶ͕֬ఆ͢Δ͔ɺ໊લղܾ͕׬ྃ͢Δ͔ɺ λΠϜΞ΢τ͢Δ·ͰॲཧΛϒϩοΫ
  14. ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ ऴྃঢ়ଶ case state when :success break connected_socket when :failure

    raise last_error when :timeout raise Errno::ETIMEDOUT, "user specified timeout" end TVDDFTT ➡︎ ઀ଓʹ੒ޭͨ͠ιέοτΛฦ͢ GBJMVSF ➡︎ ࠷ޙʹิ଍ͨ͠ΤϥʔͰྫ֎Λൃੜͤ͞Δ UJNFPVU ➡︎ λΠϜΞ΢τΛද͢ྫ֎Λൃੜͤ͞Δ ˞઀ଓʹ੒ޭͨ͠ιέοτΛฦͨ͢Ίͷঢ়ଶ ˞͢΂ͯͷ໊લղܾͱ઀ଓʹࣦഊ͠ɺྫ֎Λൃੜͤ͞ΔͨΊͷঢ়ଶ ˞ϢʔβʔࢦఆͷλΠϜΞ΢τ͕ൃੜ͠ɺྫ֎Λൃੜͤ͞ΔͨΊͷঢ়ଶ
  15. ͜Ε·Ͱͷ͋Β͢͡4PDLFUUDQͷ࣮૷ def self.tcp(host, port, ...) # ... state = :start

    loop do case state when :start then when :v4w then when :v6c, :v4c, :v46c then when :v46w then when :success then when :failure then when :timeout then end end end ׬੒ ໊લղܾΛ։࢝͢Δ IPv6ͷ໊લղܾ׬ྃΛ଴ػ͢Δ ઀ଓΛ։࢝͢Δ ઀ଓঢ়ଶͷ֬ఆͱ໊લղܾͷ׬ྃΛ଴ػ͢Δ ઀ଓʹ੒ޭͨ͠ιέοτΛฦ͢ ྫ֎Λൃੜͤ͞Δ λΠϜΞ΢τྫ֎Λൃੜͤ͞Δ
  16. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next (hostname_resolution_waiting, nil, nil, remaining) ઌʹղܾͰ͖ͨΞυϨεϑΝϛϦʹΑͬͯ࣍ͷঢ়ଶΛܾఆ ˞໊લղܾΛ։࢝͢ΔͨΊͷঢ়ଶ TUBSUઌʹ໊લղܾ͕׬ྃͨ͠ͷ͕*1Wͩͬͨͷ͔ɺ *1Wͩͬͨͷ͔ʹΑͬͯɺ࣍ͷঢ়ଶΛ൑அ͍ͯ͠Δ ʮ࣮૷Λঢ়ଶભҠʹدͤ͗͢ʯͷྫTUBSU ໊લղܾͷ݁ՌΛऔಘ
  17. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next (hostname_resolution_waiting, nil, nil, remaining) ͜ͷ࣌఺Ͱ*1W*1Wͱ΋ʹ ໊લղܾ͕׬͍ྃͯͨ͠ΒͲ͏ͳΔ   ˞໊લղܾΛ։࢝͢ΔͨΊͷঢ়ଶ ʮ࣮૷Λঢ়ଶભҠʹدͤ͗͢ʯͷྫTUBSU
  18. case state when :start # ... hostname_resolved, _, = IO.select(

    # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end selectable_addrinfos.add(family_name, res) # ... next ʮ࣮૷Λঢ়ଶભҠʹدͤ͗͢ʯͷྫTUBSU ϝΠϯεϨου͸*0TFMFDUͷ଴ػΛղআ͠ɺΩϡʔͷ ઌ಄͔Βͻͱͭऔಘ͢Δ ઌ಄͸*1Wͷ໊લղܾ݁Ռ  ϝΠϯεϨου͸औಘͰ͖ͨΞυϨεϑΝϛϦ͔Β ࣍ͷঢ়ଶΛ൑அ͢ΔͨΊɺ͜ͷ৔߹͸WX΁ભҠ͢Δɻ (hostname_resolution_waiting, nil, nil, remaining) Ωϡʔͷઌ಄Λऔಘ औಘͨ͠ΞυϨεϑΝϛϦ͕*1WͳͷͰɺ ࣍ͷঢ়ଶΛWXͱ൑அͯ͠͠·͏ ˞໊લղܾΛ։࢝͢ΔͨΊͷঢ়ଶ
  19. case state when :v4w ipv6_resolved, _, = IO.select( if ipv6_resolved

    family_name, res = hostname_resolution_queue.get selectable_addrinfos.add(family_name, res) unless res.is_a? E state = :v46c else state = :v4c end next ˞ઌʹ*1WΛղܾͰ͖ͨ৔߹ʹ*1Wͷ໊લղܾΛ଴ػ͢ΔͨΊͷঢ়ଶ WXʹͯɺ*1W͸͢ͰʹղܾࡁΈͰ͋Δʹ΋ؔΘΒͣ *1Wͷ໊લղܾΛ଴ػ͢ΔͨΊʹ*0TFMFDUΛݺͼग़͢  ෆཁͳ*0TFMFDUͷݺͼग़͕͠ൃੜ͍ͯ͠Δ ͢Ͱʹ*1W͸ղܾࡁΈͳͷʹɺෆཁʹ*0TFMFDUΛݺͼग़͍ͯ͠Δ (hostname_resolution_waiting, nil, nil, RESOLUTION_DELAY) ʮ࣮૷Λঢ়ଶભҠʹدͤ͗͢ʯͷྫWX Ωϡʔͷઌ಄Λऔಘ Exception
  20. Ͳ͏ͯ͜͠͏ͳͬͨ case state when :start # ... hostname_resolved, _, =

    IO.select( # ... family_name, res = hostname_resolution_queue.get # ... state = case family_name when :ipv6 then :v6c when :ipv4 then :v4w end # ... next (hostname_resolution_waiting, nil, nil, remaining) ঢ়ଶભҠΛݟͨ໨ͷ··࣮૷ͨ݁͠ՌɺҰͭͷঢ়ଶ͔Β͸ ඞͣҰͭͷঢ়ଶ΁ભҠ͢Δͱ͍͏લఏͷ࣮૷ʹͳ͍ͬͯΔɻ Ұํɺ࣮ࡍʹ͸͜ͷྫͷΑ͏ʹʮঢ়ଶͷॏͶ߹Θͤʯ͕ ൃੜ͠͏Δɻ TUBSU͔ΒWDʹભҠ͢ΔͨΊͷ৚݅ͱ WXʹભҠ͢ΔͨΊͷ৚͕݅ಉ࣌ʹຬͨ͞Ε͏Δ Ұͭͷঢ়ଶ͔Β͸ඞͣҰͭͷঢ়ଶ΁ભҠ͢Δ  ʮঢ়ଶͷॏͶ߹Θͤʯ͕ൃੜ͢ΔՄೳੑ͕ ߟྀ͞Ε͍ͯͳ͍ ˞໊લղܾΛ։࢝͢ΔͨΊͷঢ়ଶ
  21. )&WରԠ4PDLFUUDQ վ ͷ֓؍ def self.tcp(host, port, ...) loop do end

    end ໊લղܾͷ։࢝ if ઀ଓ։࢝ͷ৚݅Λຬ͍ͨͯ͠Δ then ઀ଓΛ։࢝ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>) if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn) if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ࣍ͷϧʔϓʹೖΔ͜ͱ͕Ͱ͖ͳ͍ then ྫ֎Λൃੜͤ͞Δ λΠϜΞ΢τม਺ͷॳظԽ
  22. def self.tcp(host, port, ...) loop do end end ໊લղܾͷ։࢝ if

    ઀ଓ։࢝ͷ৚݅Λຬ͍ͨͯ͠Δ then ઀ଓΛ։࢝ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>) if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn) if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ࣍ͷϧʔϓʹೖΔ͜ͱ͕Ͱ͖ͳ͍ then ྫ֎Λൃੜͤ͞Δ λΠϜΞ΢τม਺ͷॳظԽ )&WରԠ4PDLFUUDQ վ ͷ֓؍ ϧʔϓͷͨͼʹ্͔Βॱʹ࣮ߦ͞ΕΔ ঢ়ଶ؅ཧΛ΍Ίͨ͜ͱʹΑΓϧʔϓ಺ͷDBTF͕ফ͑ ୅ΘΓʹJGจʹΑΔ৚݅෼ذ͕௥Ճ͞Ε͍ͯΔ
  23. )&WରԠ4PDLFUUDQ վ ͷ࣮૷ϧʔϓʹೖΔલ def self.tcp(host, port, ...) # ... resolution_delay_expires_at

    = nil connection_attempt_delay_expires_at = nil # ... loop do # ... end end λΠϜΞ΢τΛ؅ཧ͢Δม਺ ϧʔϓʹೖΔલᶃ ৽ͨʹλΠϜΞ΢τΛ؅ཧ͢Δม਺Λ༻ҙɻ ͦΕͧΕʹॳظ஋ͱͯ͠OJMΛηοτ͢Δ ϧʔϓΛ։࢝  SFTPMVUJPO@EFMBZ@FYQJSFT@BU *1Wͷ໊લղܾΛNT଴ػ͢ΔͨΊͷ࣌ؒ 3FTPMVUJPO%FMBZ Λ֨ೲ͢Δม਺ DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BU ࣍ͷ઀ଓͷ։࢝·ͰNT଴ػ͢ΔͨΊͷ࣌ؒ $POOFDUJPO"UUFNQU%FMBZ Λ֨ೲ͢Δม਺
  24. def self.tcp(host, port, ...) # ... resolution_delay_expires_at = nil connection_attempt_delay_expires_at

    = nil # ... loop do # ... end end )&WରԠ4PDLFUUDQ վ ͷ࣮૷ϧʔϓʹೖΔલ λΠϜΞ΢τΛ؅ཧ͢Δม਺  ˞͜ΕΒͷม਺ʹ͸ͦΕͧΕɺ ɾλΠϜΞ΢τΛ଴ͭॲཧ͕ൃੜͨ͠ࡍʹʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯͷ͕࣌ؒηοτ͞ΕΔ ɾηοτ͕ͨ࣌ؒ͠ݱࡏ࣌ࠁΑΓ΋աڈ࣌ؒʹͳͬͨΓ଴ػ͕ෆཁʹͳΔͱOJM͕ηοτ͞ΕΔ ϧʔϓΛ։࢝
  25. )&WରԠ4PDLFUUDQ վ ͷ࣮૷ϧʔϓʹೖΔલ def self.tcp(host, port, ...) # ... hostname_resolution_threads.concat(

    resolving_family_names.map { |family| th_args = [family, host, port, hostname_resolution_result] thread = Thread.new(*th_args) { |*th_args | resolve_hostname(*th_args) } Thread.pass thread } ) # ... loop do # ... end end ϧʔϓʹೖΔલᶄ໊લղܾΛฒߦʹ։࢝͢Δ  มߋલ͸ϧʔϓͷத TUBSU Ͱߦͳ͍͕ͬͯͨɺ ࣮ࡍʹ͸શମͰҰճ͔͠ߦΘͳ͍ॲཧͷͨΊ͜͜ʹҠಈ ΞυϨεϑΝϛϦ͝ͱʹεϨουΛੜ੒໊ͯ͠લղܾΛ։࢝ ϧʔϓΛ։࢝
  26. def self.tcp(host, port, ...) # ... loop do # ...

    end end )&WରԠ4PDLFUUDQ վ ͷ࣮૷઀ଓͷ։࢝ ໊લղܾͷ։࢝ λΠϜΞ΢τม਺ͷॳظԽ ϧʔϓΛ։࢝ ଓ͍ͯɺϧʔϓʹೖΔ
  27. )&WରԠ4PDLFUUDQ վ ͷ࣮૷઀ଓͷ։࢝ loop do if resolution_store.any_addrinfos? && !resolution_delay_expires_at &&

    !connection_attempt_delay_expires_at while (addrinfo = resolution_store.get_addrinfo) # end # ... end end ϧʔϓͷதͰ͸·ͣ ʮ઀ଓ։࢝ͷ৚݅Λຬ͍ͨͯ͠Δ͔Ͳ͏͔ʯΛ֬ೝ͢Δ ɾղܾࡁΈͷΞυϨεͷࡏݿ͕͋Δ͜ͱ ɾ͔ͭ*1Wͷ໊લղܾΛ଴ػதͰ͸ͳ͍͜ͱ ɾ͔ͭ઀ଓ։࢝ͷ଴ػதͰ͸ͳ͍͜ͱ ઀ଓΛ։࢝͢ΔͨΊͷॲཧ ϧʔϓΛ։࢝ ઀ଓ։࢝ͷ৚݅Λຬ͍ͨͯ͠Δ 
  28. loop do # ... while (addrinfo = resolution_store.get_addrinfo) # ...

    socket = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) socket.bind(local_addrinfo) if local_addrinfo result = socket.connect_nonblock(addrinfo, exception: false) if result == :wait_writable # ... CONNECTION_ATTEMPT_DELAY # ... # ... end end # ... end ৚݅Λຬͨ͢৔߹ɺղܾࡁΈͷΞυϨεΛҰͭऔಘ͠ɺ ϊϯϒϩοΩϯάϞʔυͰ઀ଓΛ։࢝ ΞυϨεΛऔಘ ઀ଓΛ։࢝ )&WରԠ4PDLFUUDQ վ ͷ࣮૷઀ଓͷ։࢝
  29. loop do # ... while (addrinfo = resolution_store.get_addrinfo) # ...

    socket = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) socket.bind(local_addrinfo) if local_addrinfo result = socket.connect_nonblock(addrinfo, exception: false) # ... if result == :wait_writable connection_attempt_delay_expires_at = now + CONNECTION_ATTEMPT_DELAY # ... connecting_sockets[socket] = addrinfo # ... end end # ... end DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BUʹ ࣍ͷ઀ଓ։࢝·ͰͷλΠϜΞ΢τ࣌ؒΛηοτ͢Δ ݱࡏ࣌ࠁͷNTޙΛηοτ )&WରԠ4PDLFUUDQ վ ͷ࣮૷઀ଓͷ։࢝
  30. loop do # ... while (addrinfo = resolution_store.get_addrinfo) # ...

    socket = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) socket.bind(local_addrinfo) if local_addrinfo result = socket.connect_nonblock(addrinfo, exception: false) # ... if result == :wait_writable connection_attempt_delay_expires_at = now + CONNECTION_ATTEMPT_DELAY # ... connecting_sockets[socket] = addrinfo # ... end end # ... end ઀ଓʹ࢖ͬͨιέοτΛอଘͨ͠Βɺ͜ͷJGจΛൈ͚Δ )&WରԠ4PDLFUUDQ վ ͷ࣮૷઀ଓͷ։࢝ ઀ଓʹ࢖༻ͨ͠ιέοτΛอଘ
  31. loop do # ... hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier,

    connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) # ... end )&WରԠ4PDLFUUDQ վ ͷ࣮૷໊લղܾͱ઀ଓͷ଴ػ ઀ଓঢ়ଶͷ֬ఆ·ͨ͸໊લղܾͷ׬ྃΛ଴ػ ଓ͍ͯɺ*0TFMFDUΛ༻͍ͯ઀ଓঢ়ଶͷ֬ఆ͔ ໊લղܾͷ׬ྃΛ଴ػ͢Δ  มߋલͷ4PDLFUUDQͷWXͰߦ͍ͬͯͨॲཧͱಉ͡ if ઀ଓ։࢝ͷ৚݅Λຬ͍ͨͯ͠Δ then ઀ଓΛ։࢝ if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn) if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ
  32. )&WରԠ4PDLFUUDQ վ ͷ࣮૷઀ଓঢ়ଶͷ֬ೝ loop do # ... if writable_sockets&.any? while

    (writable_socket = writable_sockets.pop) is_connected = is_windows_environment || ( sockopt = writable_socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR) sockopt.int.zero? ) if is_connected connecting_sockets.delete writable_socket return writable_socket else # ... end end end # ... end *0TFMFDU͕଴ػΛղআͨ͠Βɺ࣮ߦ݁Ռͱͯ͠ ʮ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ͔Ͳ͏͔ʯΛ֬ೝ ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ  IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>)
  33. )&WରԠ4PDLFUUDQ վ ͷ࣮૷઀ଓঢ়ଶͷ֬ೝ loop do # ... if writable_sockets&.any? while

    (writable_socket = writable_sockets.pop) is_connected = is_windows_environment || ( sockopt = writable_socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR) sockopt.int.zero? ) if is_connected connecting_sockets.delete writable_socket return writable_socket else # ... end end end # ... end ৚͕݅ຬͨ͞Ε͍ͯΔ৔߹͸ɺର৅ͷιέοτͷ ઀ଓঢ়ଶΛ֬ೝ͠ɺద੾ͳॲཧΛߦ͏ ઀ଓʹ੒ޭ͍ͯ͠Δ  ઀ଓͰ͖ͨιέοτΛฦ͢ ઀ଓঢ়ଶͷ֬ೝ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>)
  34. loop do # ... if hostname_resolved&.any? while (family_and_result = hostname_resolution_result.get)

    family_name, result = family_and_result if result.is_a? Exception # ... else resolution_store.add_resolved(family_name, result) end # ... end end # ... end ͞Βʹ*0TFMFDUͷ࣮ߦ݁Ռͱͯ͠ ʮ໊લղܾ͕׬͍ྃͯ͠Δ͔Ͳ͏͔ʯΛ֬ೝ )&WରԠ4PDLFUUDQ վ ͷ࣮૷໊લղܾͷ׬ྃ ໊લղܾ͕׬ྃͨ͠  IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>)
  35. loop do # ... if hostname_resolved&.any? while (family_and_result = hostname_resolution_result.get)

    family_name, result = family_and_result if result.is_a? Exception # ... else resolution_store.add_resolved(family_name, result) end # ... end end # ... end ৚͕݅ຬͨ͞Ε͍ͯΕ͹ɺղܾͨ͠ΞυϨεΛ औಘͰ͖Δ͔͗Γऔಘͯ͠อଘ͢Δɻ )&WରԠ4PDLFUUDQ վ ͷ࣮૷໊લղܾͷ׬ྃ ΞυϨεΛऔಘͰ͖ΔݶΓऔಘ औಘͰ͖ͨΞυϨεΛอଘ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>)
  36. loop do # ... if hostname_resolved&.any? while (family_and_result = hostname_resolution_result.get)

    # ... if resolution_store.resolved?(:ipv4) if resolution_store.resolved?(:ipv6) hostname_resolution_notifier = nil # ... user_specified_resolv_timeout_at = nil elsif resolution_store.resolved_successfully?(:ipv4) resolution_delay_expires_at = now + RESOLUTION_DELAY end end end end # ... end *1Wͷ໊લղܾ͕׬͓ྃͯ͠Γɺ͔ͭ*1Wͷ໊લղܾ͕ ׬͍ྃͯ͠ͳ͍৔߹͸SFTPMVUJPO@EFMBZ@FYQJSFT@BUʹ *1Wͷ໊લղܾΛ଴ػ͢Δ࣌ؒΛηοτ͢Δ )&WରԠ4PDLFUUDQ վ ͷ࣮૷໊લղܾͷ׬ྃ *1Wͷ໊લղܾ͕׬ྃͨ͠  ͔ͭɺ*1Wͷ໊લղܾ͕׬͍ྃͯ͠ͳ͍ ݱࡏ࣌ࠁͷNTޙΛηοτ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>)
  37. loop do # ... if hostname_resolved&.any? while (family_and_result = hostname_resolution_result.get)

    # ... if resolution_store.resolved?(:ipv4) if resolution_store.resolved?(:ipv6) hostname_resolution_notifier = nil resolution_delay_expires_at = nil user_specified_resolv_timeout_at = nil elsif resolution_store.resolved_successfully?(:ipv4) resolution_delay_expires_at = now + RESOLUTION_DELAY end end end end # ... end *1W*1Wͱ΋ʹ໊લղܾ͕׬͍ྃͯ͠Δ৔߹͸ SFTPMVUJPO@EFMBZ@FYQJSFT@BUʹOJMΛηοτ͢Δ )&WରԠ4PDLFUUDQ վ ͷ࣮૷໊લղܾͷ׬ྃ *1Wͷ໊લղܾ͕׬ྃͨ͠  ͔ͭɺ*1Wͷ໊લղܾ͕׬ྃͨ͠ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>) OJMΛηοτ
  38. loop do # ... if resolution_store.empty_addrinfos? if connecting_sockets.empty? && resolution_store.resolved_all_families?

    raise last_error end if (expired?(now, user_specified_resolv_timeout_at) || ...) && (expired?(now, user_specified_connect_timeout_at) || ...) raise Errno::ETIMEDOUT, 'user specified timeout' end end end ϧʔϓͷ࠷ޙʹɺ ʮ࣍ͷϧʔϓʹೖΔ͜ͱ͕Ͱ͖Δ͔Ͳ͏͔ʯ֬ೝ )&WରԠ4PDLFUUDQ վ ͷ࣮૷࣍ͷϧʔϓ΁ ࣍ͷϧʔϓʹೖΔ͜ͱ͕Ͱ͖Δ  if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn)
  39. loop do # ... if resolution_store.empty_addrinfos? if connecting_sockets.empty? && resolution_store.resolved_all_families?

    raise last_error end if (expired?(now, user_specified_resolv_timeout_at) || ...) && (expired?(now, user_specified_connect_timeout_at) || ...) raise Errno::ETIMEDOUT, 'user specified timeout' end end end ɾղܾࡁΈͷΞυϨεͷࡏݿ͕ͳ͍ ɾ͔ͭɺ઀ଓதͷιέοτ͕ͳ͍ ɾ͔ͭɺ͢΂ͯͷ໊લղܾ͕ऴΘ͍ͬͯΔ৔߹͸ ͜ΕҎ্࣮ߦͰ͖Δॲཧ͕ͳ͍ͨΊɺྫ֎Λൃੜͤ͞Δ )&WରԠ4PDLFUUDQ վ ͷ࣮૷࣍ͷϧʔϓ΁ if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn) ͜ΕҎ্࣮ߦͰ͖Δॲཧ͕ͳ͍  ࠷ޙʹิ଍ͨ͠ΤϥʔͰྫ֎Λൃੜͤ͞Δ
  40. loop do # ... if resolution_store.empty_addrinfos? if connecting_sockets.empty? && resolution_store.resolved_all_families?

    raise last_error end if (expired?(now, user_specified_resolv_timeout_at) || ...) && (expired?(now, user_specified_connect_timeout_at) || ...) raise Errno::ETIMEDOUT, 'user specified timeout' end end end ϢʔβʔࢦఆͷλΠϜΞ΢τ͕௒ա͍ͯ͠Δ৔߹ɺ λΠϜΞ΢τΛද͢ྫ֎Λൃੜͤ͞Δɻ )&WରԠ4PDLFUUDQ վ ͷ࣮૷࣍ͷϧʔϓ΁ ϢʔβʔࢦఆͷλΠϜΞ΢τΛ௒աࡁΈ  λΠϜΞ΢τΛද͢ྫ֎Λൃੜͤ͞Δ if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn)
  41. loop do # ... if resolution_store.empty_addrinfos? if connecting_sockets.empty? && resolution_store.resolved_all_families?

    raise last_error end if (expired?(now, user_specified_resolv_timeout_at) || ...) && (expired?(now, user_specified_connect_timeout_at) || ...) raise Errno::ETIMEDOUT, 'user specified timeout' end end end ͦΕҎ֎ͷ৔߹͸࣍ͷϧʔϓʹਐΉ 5PCFDPOUJOVFE )&WରԠ4PDLFUUDQ վ ͷ࣮૷࣍ͷϧʔϓ΁ ࣍ͷϧʔϓ΁ if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn)
  42. def self.tcp(host, port, ...) loop do end end ໊લղܾͷ։࢝ if

    ઀ଓ։࢝ͷ৚݅Λຬ͍ͨͯ͠Δ then ઀ଓΛ։࢝ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>) if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn) if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ࣍ͷϧʔϓʹೖΔ͜ͱ͕Ͱ͖ͳ͍ then ྫ֎Λൃੜͤ͞Δ λΠϜΞ΢τม਺ͷॳظԽ )&WରԠ4PDLFUUDQ վ ɿ࢒Γͷ՝୊  
  43. loop do # ... hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier,

    connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) # ... end มߋޙͷ4PDLFUUDQͰ͸ɺϧʔϓͷதͰҰճ͚ͩ *0TFMFDUΛݺͼग़͢ɻ͜ͷ*0TFMFDUͰ଴ػ͢Δ΂͖ ࣌ؒ͸ɺͦͷͱ͖ͷঢ়گʹΑͬͯҟͳΔ ࢒Γͷ՝୊ɿ*0TFMFDUͷ଴ػ࣌ؒ ଴ػ࣌ؒ ϧʔϓͷͨͼʹมΘΔՄೳੑ͕͋Δʜ   ྫ  *1W*1Wͱ΋ʹ໊લղܾத ➡︎ ແظݶ *1W໊લղܾޙɺ*1W໊લղܾΛ଴ػ͢Δ ➡︎ NT ઀ଓΛ։࢝ޙɺ࣍ͷ઀ଓ։࢝·Ͱ଴ػ͢Δ ➡︎ NT
  44. loop do # ... ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at ||

    connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max end hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) # ... end *0TFMFDUʹ౉ͨ͢Ίͷద੾ͳ଴ػ࣌ؒΛબ୒͢Δ ϩδοΫΛಋೖ ࢒Γͷ՝୊ɿ*0TFMFDUͷ଴ػ࣌ؒ ʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯΛબ୒
  45. loop do # ... ends_at = if resolution_store.any_addrinfos? hostname_resolved, writable_sockets,

    except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, second_to_timeout(current_clock_time, ends_at), ) is_windows_environment ? connecting_sockets.keys : nil, # ... end ʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯΛબ୒͢Δ ղܾࡁΈͷΞυϨεͷࡏݿ͕͋Δ৔߹  ʮղܾࡁΈͷΞυϨεͷࡏݿ͕͋Δʯঢ়گͱ͸ɿ ɾ3FTPMVUJPO%FMBZத ɹ *1Wͷ໊લղܾ͕׬ྃࡁΈɺ͔ͭ઀ଓ։࢝લʹ*1Wͷ໊લղܾΛ଴ػத  ɾ$POOFDUJPO"UUFNQU%FMBZத͋Δ͍͸௒աࡁΈ ɹ ͢ͰʹҰͭҎ্઀ଓΛ։࢝ࡁΈɺ͔ͭղܾࡁΈͷΞυϨεͷࡏݿ͕͋Δ  ɹ  ͷͲͪΒ͔
  46. loop do # ... ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at hostname_resolved,

    writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, second_to_timeout(current_clock_time, ends_at), ) is_windows_environment ? connecting_sockets.keys : nil, # ... end ʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯΛબ୒͢Δ ղܾࡁΈͷΞυϨεͷࡏݿ͕͋Δ৔߹  3FTPMVUJPO%FMBZதɿ ม਺SFTPMVUJPO@EFMBZ@FYQJSFT@BUʹ ηοτ͞Ε͍ͯΔλΠϜΞ΢τ஋ΛฦΓ஋ͱ͢Δ
  47. loop do # ... ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at ||

    connection_attempt_delay_expires_at hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, second_to_timeout(current_clock_time, ends_at), ) is_windows_environment ? connecting_sockets.keys : nil, # ... end ʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯΛબ୒͢Δ ղܾࡁΈͷΞυϨεͷࡏݿ͕͋Δ৔߹  $POOFDUJPO"UUFNQU%FMBZத͋Δ͍͸௒աࡁΈɿ ม਺DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BUʹ ηοτ͞Ε͍ͯΔλΠϜΞ΢τ஋ ͋Δ͍͸OJM ΛฦΓ஋ͱ͢Δ
  48. loop do # ... ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at ||

    connection_attempt_delay_expires_at else hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, second_to_timeout(current_clock_time, ends_at), ) # ... is_windows_environment ? connecting_sockets.keys : nil, end ʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯΛબ୒͢Δ  ʮղܾࡁΈͷΞυϨεͷࡏݿ͕ͳ͍ʯঢ়گͱ͸ɿ ɾ·ͩ*1W*1Wͱ΋ʹ໊લղܾ͕ऴΘ͍ͬͯͳ͍ঢ়گ ɾશͯͷղܾࡁΈͷΞυϨεѼʹ઀ଓΛ։࢝͠ɺࡏݿ͕ͳ͘ͳͬͨঢ়گ ɹ  ͷͲͪΒ͔ ղܾࡁΈͷΞυϨεͷࡏݿ͕ͳ͍৔߹
  49. loop do # ... ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at ||

    connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max end hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, second_to_timeout(current_clock_time, ends_at), ) # ... is_windows_environment ? connecting_sockets.keys : nil, end ʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯΛબ୒͢Δ ղܾࡁΈͷΞυϨεͷࡏݿ͕ͳ͍৔߹  ͍ͣΕͷ৔߹΋ɺϢʔβʔࢦఆͷλΠϜΞ΢τΛ؅ཧ͢Δม਺ʹ ֨ೲ͞Ε͍ͯΔ஋ͷେ͖͍ํΛฦ͢ ϢʔβʔࢦఆͷλΠϜΞ΢τ͕໌ࣔతʹࢦఆ͞Ε͍ͯͳ͍৔߹ɺ ͜ΕΒͷม਺ʹ͸'MPBU*/'*/*5:͕֨ೲ͞Ε͍ͯΔ ແظݶʹ଴ػ
  50. loop do # ... ends_at = if resolution_store.any_addrinfos? resolution_delay_expires_at ||

    connection_attempt_delay_expires_at else [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max end hostname_resolved, writable_sockets, except_sockets = IO.select( hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) # ... end ʮબ୒͞Εͨ଴ػ࣌ؒݱࡏ࣌ࠁʯͷࠩ෼Λ ࣮ࡍͷ଴ػ࣌ؒͱͯ͠*0TFMFDUʹ౉͢ ʮ͍ͭ·Ͱ଴ػ͢Δ͔ʯΛબ୒͢Δ ࣮ࡍͷ଴ػ࣌ؒ FOET@BU͔Βݱࡏ࣌ࠁΛҾ͍ͨࠩ෼  બ୒͞Εͨ଴ػ࣌ؒΛ֨ೲ
  51. λΠϜΞ΢τΛ؅ཧ͢Δม਺ΛϦηοτ loop do # ... hostname_resolved, writable_sockets, except_sockets = IO.select(

    hostname_resolution_notifier, connecting_sockets.keys, is_windows_environment ? connecting_sockets.keys : nil, second_to_timeout(current_clock_time, ends_at), ) now = current_clock_time if expired?(now, resolution_delay_expires_at) resolution_delay_expires_at = nil end if expired?(now, connection_attempt_delay_expires_at) connection_attempt_delay_expires_at = nil end # ... end *0TFMFDU͔Βฦ͖ͬͯͨ࣌఺ͰλΠϜΞ΢τ͕࣌ؒ աڈ࣌ؒʹͳ͍ͬͯͨ৔߹͸λΠϜΞ΢τͷ؅ཧ͕ ෆཁʹͳΔͷͰͦΕͧΕOJMΛηοτ SFTPMVUJPO@EFMBZ@FYQJSFT@BU͕աڈ࣌ؒ  DPOOFDUJPO@BUUFNQU@EFMBZ@FYQJSFT@BU͕աڈ࣌ؒ 
  52. def self.tcp(host, port, ...) loop do end end ໊લղܾͷ։࢝ if

    ઀ଓ։࢝ͷ৚݅Λຬ͍ͨͯ͠Δ then ઀ଓΛ։࢝ IO.select(<໊લղܾ>, <઀ଓ>, nil, <λΠϜΞ΢τ஋>) if ઀ଓঢ়ଶ͕֬ఆͨ͠ιέοτ͕͋Δ then ઀ଓ֬ೝɹ(੒ޭ͍ͯͨ͠Βreturn) if ໊લղܾ͕׬ྃ then ղܾࡁΈͷIPΞυϨεΛอଘ if ࣍ͷϧʔϓʹೖΔ͜ͱ͕Ͱ͖ͳ͍ then ྫ֎Λൃੜͤ͞Δ λΠϜΞ΢τม਺ͷॳظԽ )&WରԠ4PDLFUUDQ վ ࠓ౓ͦ͜׬੒