Base TCP server class. You must subclass GenericServer and provide a run method.
Creates a new generic server from config. The default
configuration comes from default.
# File webrick/server.rb, line 94
def initialize(config={}, default=Config::General)
@config = default.dup.update(config)
@status = :Stop
@config[:Logger] ||= Log::new
@logger = @config[:Logger]
@tokens = SizedQueue.new(@config[:MaxClients])
@config[:MaxClients].times{ @tokens.push(nil) }
webrickv = WEBrick::VERSION
rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
@logger.info("WEBrick #{webrickv}")
@logger.info("ruby #{rubyv}")
@listeners = []
unless @config[:DoNotListen]
if @config[:Listen]
warn(":Listen option is deprecated; use GenericServer#listen")
end
listen(@config[:BindAddress], @config[:Port])
if @config[:Port] == 0
@config[:Port] = @listeners[0].addr[1]
end
end
end
Retrieves key from the configuration
# File webrick/server.rb, line 123
def [](key)
@config[key]
end
Adds listeners from address and port to the
server. See WEBrick::Utils.create_listeners
for details.
# File webrick/server.rb, line 131
def listen(address, port)
@listeners += Utils::create_listeners(address, port, @logger)
end
You must subclass GenericServer and implement #run which accepts a TCP client socket
# File webrick/server.rb, line 246
def run(sock)
@logger.fatal "run() must be provided by user."
end
Shuts down the server and all listening sockets. New listeners must be provided to restart the server.
# File webrick/server.rb, line 219
def shutdown
stop
@listeners.each{|s|
if @logger.debug?
addr = s.addr
@logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
end
begin
s.shutdown
rescue Errno::ENOTCONN
# when `Errno::ENOTCONN: Socket is not connected' on some platforms,
# call #close instead of #shutdown.
# (ignore @config[:ShutdownSocketWithoutClose])
s.close
else
unless @config[:ShutdownSocketWithoutClose]
s.close
end
end
}
@listeners.clear
end
Starts the server and runs the block for each connection.
This method does not return until the server is stopped from a signal
handler or another thread using stop or shutdown.
If the block raises a subclass of StandardError the exception is logged and ignored. If an IOError or Errno::EBADF exception is raised the exception is ignored. If an Exception subclass is raised the exception is logged and re-raised which stops the server.
To completely shut down a server call shutdown from ensure:
server = WEBrick::GenericServer.new # or WEBrick::HTTPServer.new begin server.start ensure server.shutdown end
# File webrick/server.rb, line 156
def start(&block)
raise ServerError, "already started." if @status != :Stop
server_type = @config[:ServerType] || SimpleServer
server_type.start{
@logger.info "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
call_callback(:StartCallback)
thgroup = ThreadGroup.new
@status = :Running
begin
while @status == :Running
begin
if svrs = IO.select(@listeners, nil, nil, 2.0)
svrs[0].each{|svr|
@tokens.pop # blocks while no token is there.
if sock = accept_client(svr)
sock.do_not_reverse_lookup = config[:DoNotReverseLookup]
th = start_thread(sock, &block)
th[:WEBrickThread] = true
thgroup.add(th)
else
@tokens.push(nil)
end
}
end
rescue Errno::EBADF, IOError => ex
# if the listening socket was closed in GenericServer#shutdown,
# IO::select raise it.
rescue StandardError => ex
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
@logger.error msg
rescue Exception => ex
@logger.fatal ex
raise
end
end
ensure
@status = :Shutdown
@logger.info "going to shutdown ..."
thgroup.list.each{|th| th.join if th[:WEBrickThread] }
call_callback(:StopCallback)
@logger.info "#{self.class}#start done."
@status = :Stop
end
}
end
Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.
If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.
If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.
If you want to help improve the Ruby documentation, please see Improve the docs, or visit Documenting-ruby.org.