ruby gserver源码阅读

gserver作为通用服务器的实现,最关键的就是start方法

def start(maxConnections = -1)
  raise "running" if !stopped?
  @shutdown = false
  @maxConnections = maxConnections if maxConnections > 0
  @@servicesMutex.synchronize  {
    if GServer.in_service?(@port,@host)
      raise "Port already in use: #{host}:#{@port}!"
    end
    @tcpServer = TCPServer.new(@host,@port)
    @port = @tcpServer.addr[1]
    @@services[@host] = {} unless @@services.has_key?(@host)
    @@services[@host][@port] = self;
  }
  @tcpServerThread = Thread.new {
    begin
      starting if @audit
      while !@shutdown
        @connectionsMutex.synchronize  {
           while @connections.size >= @maxConnections
             @connectionsCV.wait(@connectionsMutex)
           end
        }
        client = @tcpServer.accept
        @connections << Thread.new(client)  { |myClient|
          begin
            myPort = myClient.peeraddr[1]
            serve(myClient) if !@audit or connecting(myClient)
          rescue => detail
            error(detail) if @debug
          ensure
            begin
              myClient.close
            rescue
            end
            @connectionsMutex.synchronize {
              @connections.delete(Thread.current)
              @connectionsCV.signal
            }
            disconnecting(myPort) if @audit
          end
        }
      end
    rescue => detail
      error(detail) if @debug
    ensure
      begin
        @tcpServer.close
      rescue
      end
      if @shutdown
        @connectionsMutex.synchronize  {
           while @connections.size > 0
             @connectionsCV.wait(@connectionsMutex)
           end
        }
      else
        @connections.each { |c| c.raise "stop" }
      end
      @tcpServerThread = nil
      @@servicesMutex.synchronize  {
        @@services[@host].delete(@port)
      }
      stopping if @audit
    end
  }
  self
end

第5-13行检查host的port是否被占用,如果没有的话,则根据host和port实例化TCPServer,并通过@@services[@host][@port]记录。

第14-65行将服务器的服务交由一个单独的线程处理,这样当当前进程退出的时候,该线程也会被强制退出。

第18-22行和第35-38行是用来管理线程池的,当要加入一个新的线程之前,检查当前的线程数量,如果达到线程数最大值,则挂起当前线程;当删除一个线程时,通知某个被挂起的线程继续执行。

第23-41行是一个tcp服务的全过程,获取client的连接,启动一个线程来处理当前的连接,执行serve方法,最终关闭当前的连接。

第46-63行是tcp服务器关闭时执行的过程,服务器关闭有两种方法:

一是shutdown,tcp服务器会等待所有的线程都执行完毕再关闭

二是close,tcp服务器会中断所有的线程,强制关闭

其它的方法,如shutdown, close都写得很简单,不再一一叙述。

Posted in  ruby


blog comments powered by Disqus
Fork me on GitHub