我对使用IO.select
的一些套接字代码感到困惑,它在运行后没有清理:
require 'socket'
def run(socket)
loop do
begin
selections, _, _ = IO.select([socket])
io, _ = selections
begin
connection, _ = io.accept
puts "ACCEPTED: #{connection.inspect}"
ensure
puts "CLOSING: #{connection.inspect}"
connection.close
puts "CLOSED: #{connection.inspect}"
end
rescue Interrupt
puts "INTERRUPTED"
break
end
end
end
begin
socket = Socket.new(:INET, :STREAM)
socket.bind(Socket.pack_sockaddr_in(5000, '0.0.0.0'))
socket.listen(4)
puts "LISTENING: #{socket.inspect}"
run(socket)
ensure
puts "CLOSING: #{socket.inspect}"
socket.close
puts "CLOSED: #{socket.inspect}"
end
运行程序并发送中断信号可以打印:
ruby script.rb
LISTENING: #<Socket:fd 7>
^CINTERRUPTED
CLOSING: #<Socket:fd 7>
CLOSED: #<Socket:(closed)>
再次运行程序并发出请求:
ruby script.rb
LISTENING: #<Socket:fd 7>
curl 0.0.0.0:5000
ACCEPTED: #<Socket:fd 8>
CLOSING: #<Socket:fd 8>
CLOSED: #<Socket:(closed)>
curl: empty reply from server
^CINTERRUPTED
CLOSING: #<Socket:fd 7>
CLOSED: #<Socket:(closed)>
尽管调试信息看起来很正常 - 再次快速运行程序会给出:
ruby script.rb
script.rb:25:in `bind': Address already in use - bind(2) for 0.0.0.0:5000 (Errno::EADDRINUSE)
from script.rb:25:in `<main>'
套接字最终会再次绑定(在运行之间有一个长时间的停顿)。有什么不清理?日志使得每个呼叫都被清理干净。