Working with TCP Sockets 読書メモ 第8章 コネクションの多重化

目次


コネクションの多重化

  • コネクションの多重化とは、同時に複数のソケットを使用すること

select(2)

# ※擬似コード
# コネクションが配列で与えられるとする
connections = [<TCPSocket>, <TCPSocket>, <TCPSocket>]

loop do
  # select(2) を使ってコネクションが読み込み可能か調べる
  ready = IO.select(connections)

  # 利用可能なコネクションからのみデータを読み取る
  readable_connections = ready[0]
  readable_connections.each do |conn|
    data = con.readpartial(4096)
    process(data)
  end
end
  • IO.selectを使うことで、複数のコネクションを扱う際のオーバーヘッドを削減できる
    • 内部ではselect(2)が使われている
  • IO.selectは最大で4つ引数を取る( リファレンス )
for_reading = [<TCPSocket>, <TCPSocket>, <TCPSocket>]
for_writing = [<TCPSocket>, <TCPSocket>, <TCPSocket>]

IO.select(for_reading, for_writing, for_reading)
  • 第1引数は読み込みを行いたいIOオブジェクトの配列
  • 第2引数は書き込みを行いたいIOオブジェクトの配列
  • 第3引数は例外待ちを行いたいIOオブジェクトの配列

  • IO.selectは2次元配列を返す

  • 第1要素は、第1引数で渡したIOオブジェクトのうち、ブロックせずに読み込み可能なものの配列
  • 第2要素は、第2引数で渡したIOオブジェクトのうち、ブロックせずに書き込み可能なものの配列
  • 第3要素は、第3引数で渡したIOオブジェクトのうち、例外待ち可能なものの配列

  • IO.selectは、処理可能なIOオブジェクトがないとブロックする

  • 第4引数にタイムアウトの秒数を渡すと、指定した時間だけ待つ
    • タイムアウトの秒数が経過したらnilが返る

読み書き以外のイベント

  • IO.selectで発生するイベントは他にも以下のようなものがある

EOF

  • 読み込み待ちの最中にEOFを受け取ると、EOFErrorが発生するか、nilが返る

Accept

  • 読み込み待ち中にコネクションが来ると、読み込み可能なソケットの配列の中に含まれて返却される

Connect

  • connect_nonblockErrno::EINPROGRESSの際に、バックグラウンドの接続が完了したか確認できる
require 'socket'

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

begin
  socket.connect_nonblock(remote_addr)
rescue Errno::EINPROGRESS
  IO.select(nil, [socket])

  begin
    socket.connect_nonblock(remote_addr)
  rescue Errno::EISCONN
    # 接続成功
  rescue Errno::ECONNREFUSED
    # リモートホストから接続拒否
  end
end

ハイパフォーマンスな多重化

  • Rubyでは多重化のための機能はIO.selectしか提供されていない
  • モダンなOSでは様々な多重化方法を提供しているが、select(2)は最も古くパフォーマンスに劣る
  • select(2)は監視対象のコネクション数が増えると線形的にパフォーマンスが低下する
  • poll(2)はselect(2)の代替だがそれほどの差はない
  • (Linux)epoll(2) または (BSD)kqueue(2) は、select(2)およびpoll(2)のモダンな代替である
  • EventMachineのようなハイパフォーマンスなネットワークライブラリはepoll(2)やkqueue(2)を使っている
  • nio4r等のgemを使うことで、Rubyでもepoll(2)等を使えるようになる

コメントをどうぞ

コメントを残す