Working with TCP Sockets 読書メモ 第11章 タイムアウト

Working with TCP Sockets 読書メモ 目次

タイムアウト

使用できない選択肢

  • Ruby組み込みのtimeoutライブラリはソケットと同時に使うのに適していない
  • SNDTIMEO/RCVTIMEOとソケットオプションの組み合わせも理想的ではない

IO.select

  • IO.selectはタイムアウトにも使うことができる
require 'socket'
require 'timeout' # Timeout::Error を使うためにrequire

timeout = 5 # seconds

Socket.tcp_server_loop(4481) do |connection|
  begin
    # 最初のread(2)を実行する
    # すでにデータがある状態で select(2) を実行するのを避けるため
    connection.read_nonblock(4096)

  rescue Errno::EAGAIN
    # 読み込み可能になるまでモニターする
    if IO.select([connection], nil, nil, timeout)
      # IO.select がnilを返さなかった => ソケットは読み込み可能
      retry
    else
      puts 'timeout'
      raise Timeout::Error
    end
  end

  connection.close
end

acceptのタイムアウト

server = TCPServer.new(4481)
timeout = 5 # seconds

begin
  server.accept_nonblock
rescue Errno::EAGAIN
  if IO.select([server], nil, nil, timeout)
    retry
  else
    raise Timeout::Error
  end
end

connectのタイムアウト

require 'socket'
require 'timeout'

socket = Socket.new(:INET, :STREAM)
remote_addr = Socket.pack_sockaddr_in(80, 'google.com')
timeout = 5 # seconds

begin
  socket.connect_nonblock(remote_addr)
rescue Errno::EINPROGRESS
  if IO.select(nil, [socket], nil, timeout)
    retry
  else
    raise Timeout::Error
  end
rescue Errno::EISCONN
  # connectが正常に完了
end

socket.write('hi')
socket.close

コメントを残す

コメントを残す