为什么我的服务器不能打开文件?

时间:2013-09-10 19:33:04

标签: ruby

我一直在研究这段代码,由于某种原因服务器无法打开索引文件,我无法理解为什么。我检查了其他人的代码,看起来没有区别。

这是我的代码:

require 'socket'

class Server

  def initialize (base, request, server_name, session, charset)
    @base = base
    @request = request
    @charset = charset
    @server_name = server_name
    @session = session
    serve()
  end
  def serve ()
    access_log()
    getAddress()
    @contentType = getContentType()
    @session.print "HTTP/1.1 200 OK\r\nServer: #{@server_name}\r\nContent-Type: #{@contentType}; charset=@{charset}\r\n\r\n"
    getFile()
    @base = nil
    @request = nil
    @server_name = nil
    @contentType
    @session.close
    puts "Session Ended\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
    @session = nil
  end
  def access_log ()
    log = File.open(@base + "data/access_log.txt", "w")
    log.puts "#{Time.now.localtime.strftime("%Y/%m/%d %H:%M:%S")} #{@session.peeraddr[2]}:#{@session.peeraddr[1]} #{@request}" unless log == nil
    log.close
    log = nil
  end
  def getAddress ()
    @src = @request
    @src.gsub!(/GET /, '').gsub!(/ HTTP.*/, '')
    @src.strip
    @src = @base + "root" + @src
    @src.gsub!('/', '\\')
  end
  def getContentType ()
    ext = nil
    ext = File.extname(@src)
    return "text/html"    if ext == ".html" or ext == ".htm"
    return "text/plain"   if ext == ".txt"
    return "text/css"     if ext == ".css"
    return "image/jpeg"   if ext == ".jpeg" or ext == ".jpg"
    return "image/gif"    if ext == ".gif"
    return "image/bmp"    if ext == ".bmp"
    return "text/plain"   if ext == ".rb"
    return "text/xml"     if ext == ".xml"
    return "text/xml"     if ext == ".xsl"
    #return "image/x-icon" if ext == ".ico" or ext == ".icon"
    return "text/html"
  end
  def getFile ()
      begin
    if !File.exist?(@src)
      puts "File: #{@src} could not be found"
      if @contentType.include?("image")
        file = File.open(@base + "root/server_files/broken_image.png", "r").each do |code|
          @session.puts code
        end
      else
        file = File.open(@base + "root/server_files/error404.html", "r").each do |code|
          @session.puts code
        end
      end
    else
      puts "File #{@src} was opened"
      file = File.open(@src, "r").each do |code|
        @session.puts code
      end
    end
      ensure
    file.close unless file == nil
      end
  end
end

base = "C:\\Base\\"
server_name = "Some Server"
host = "localhost"
port = 80
charset = "UFT-8"

server = TCPServer.new(host, port)
puts "~ Server hosted on #{host}:#{port} ~\n====================================\n"

loop {
  Thread.new(server.accept) do |session|
    request = session.gets
    puts "#{session.peeraddr[2]}:#{session.peeraddr[1]} #{request}"
    Server.new(base, request, server_name, session, charset)
  end
}

p = gets.chomp
server.close

1 个答案:

答案 0 :(得分:1)

代码存在问题。我不知道这些是否直接导致问题,但是有足够的代码味道,以下未经测试的更改可能有所帮助。

不要在Ruby中使用CamelCase方法名称。我们使用snake_case。

require 'socket'

class Server

  def initialize(base, request, server_name, session, charset)

    @base = base
    @request = request
    @charset = charset
    @server_name = server_name
    @session = session

    serve()

  end

  def serve

    access_log
    get_address()
    @content_type = get_content_type()
    @session.print "HTTP/1.1 200 OK\r\nServer: #{@server_name}\r\nContent-Type: #{@content_type}; charset=@{charset}\r\n\r\n"
    get_file()
    @content_type
    @session.close
    puts "Session Ended\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
    @base = @request = @server_name = @session = nil

  end

我不知道你为什么在@content_type之前的@session.close行。它不是方法调用,也不会将任何内容返回给服务器或传出数据流。

  def access_log

    File.open(File.join(@base, "data/access_log.txt"), "w") do |log|
      log.puts "#{Time.now.localtime.strftime("%Y/%m/%d %H:%M:%S")} #{@session.peeraddr[2]}:#{@session.peeraddr[1]} #{@request}"
    end

  end

Ruby的File.open需要一个块。当块退出时,文件将自动关闭。 File.join是构建路径的正确方法。 Ruby知道正确的路径分隔符并将自动使用它们,有助于使代码更具可移植性。

  def get_address

    src = @request.gsub(/GET /, '').gsub(/ HTTP.*/, '').strip
    @src = (@base + "root" + src).gsub('/', '\\')

  end

你无缘无故地做了很多gsub!。将它们链接起来,组合字符串,做最后的gsub并继续前进。

  def get_content_type()

    ext = File.extname(@src)

    content_type = case ext
                   when /\.html?/
                     "text/html" 
                   when ".txt" 
                     "text/plain"
                   when ".css" 
                     "text/css"  
                   when /\.jpe?g/
                     "image/jpeg"
                   when ".gif" 
                     "image/gif" 
                   when ".bmp" 
                     "image/bmp" 
                   when ".rb"  
                     "text/plain"
                   when /\.x[ms]l/
                     "text/xml"  
                   else
                     "text/html"
                   end

    content_type

  end

在子例程或方法中有多个returns令人困惑,所以这会清理它。最后的content_type将作为方法调用的结果返回。使用case/when可以为每个when使用多个测试,从而降低线路噪音。

  def get_file()
    begin

      if !File.exist?(@src)

        puts "File: #{@src} could not be found"
        if @content_type["image"]
          File.open(File.join(@base, "root", "server_files", "broken_image.png"), "rb") do |image|
            @session.puts image.read
          end
        else
          File.foreach(File.join(@base, "root", "server_files", "error404.html")) do |li|
            @session.puts li
          end
        end

      else

        puts "File #{@src} was opened"
        File.foreach(@src) do |li|
          @session.puts li
        end

      end

    rescue Exception => e
      puts e.message
    end
  end

如果要读取二进制文件,例如“broken_image.png”,请始终以二进制模式打开它:"rb"。否则,Ruby会认为将行结尾转换为操作系统的本机格式是可以的,这会破坏数据。此外,再次使用File方法的块形式,以便它们自动关闭。并且,使用File.join来实现可移植性。当您阅读文本文件时,请使用File.foreach逐行阅读,除非您知道它将适合可用内存; “啜饮”你的文件是不好的形式,因为它不可扩展。

end

base = "C:/Base/"
server_name = "Some Server"
host = "localhost"
port = 80
charset = "UFT-8"

server = TCPServer.new(host, port)
puts "~ Server hosted on #{host}:#{port} ~\n====================================\n"

loop {
  Thread.new(server.accept) do |session|
    request = session.gets
    puts "#{session.peeraddr[2]}:#{session.peeraddr[1]} #{request}"
    Server.new(base, request, server_name, session, charset)
  end
}

p = gets.chomp
server.close

代码更改位于:https://gist.github.com/anonymous/6515451