Working with TCP Sockets 読書メモ 第18章 スレッドごとの接続

Working with TCP Sockets 読書メモ 目次

スレッドごとの接続

スレッドとプロセス

  • スレッドの方が生成コストが低い
  • スレッドはメモリを共有するので、複数のスレッドで共有されるデータの取り扱いに注意が必要
  • (MRIでは)スレッドはプロセスごとなので、同一の処理系の中で動く
  • (MRIでは)プロセスだけが並行性(concurrency)をもっている

実装

require 'socket'
require 'thread'
require_relative 'command_handler'

module FTP
  Connection = Struct.new(:clinet) do
    CRLF = "\r\n"

    def gets
      client.gets(CRLF)
    end

    def respond(message)
      client.write(message)
      client.write(CRLF)
    end

    def close
      client.close
    end
  end

  class ThreadPerConnection
    def initialize(port = 21)
      @control_socket = TCPServer.new(port)
      trap(:INT) { exit }
    end

    def run
      Thread.abort_on_exception = true

      loop do
        conn = Connection.new(@control_socket.accept)

        Thread.new do
          conn.respond "220 OHAI"

          handler = FTP::CommandHandler.new(conn)

          loop do
            request = conn.gets

            if request
              conn.respond handler.handle(request)
            else
              conn.close
              break
            end
          end
        end
      end
    end
  end
end

server = FTP::ThreadPerConnection.new(4481)
server.run
  • 各クライアントのコネクションを別のインスタンスにしている点に注意
  • それぞれのスレッドが1つずつコネクションを処理するよう設計すべき(ベストプラクティス)

考察

  • 利点:プロセスごとの接続よりもパフォーマンスが良い
  • 欠点:(処理によっては)GILによるロックが発生しうる、スレッド数の上限が無い

ディスカッションに参加

1件のコメント

コメントをどうぞ

コメントを残す