如何使用read,readpartial和read_nonblock从ruby中的TCPServer套接字读取

Sid*_*Sid 5 ruby unix nonblocking httpserver tcpserver

我有两个关于从套接字读取的问题,以及如何在像Unicorn或Mongrel这样的Ruby服务器上进行管理

  1. 我已经知道从套接字读取不同于读取文件,并且没有发送明显的EOF消息,并且数据是无穷无尽的.那么你怎么知道何时停止阅读?我的TCPServer例如在这种情况下,当我通过http://localhost:9799浏览器访问我的服务器时,它在没有更多数据要读取之后挂起,它也不会抛出EOFError.

require 'socket'

READ_CHUNK = 1024
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
addr = Socket.pack_sockaddr_in(9799, '127.0.0.1')
socket.bind(addr)
socket.listen(Socket::SOMAXCONN)
socket.setsockopt(:SOCKET, :REUSEADDR, true)

puts "Server is listening on port = 9799"
loop do 
    connection, addr_info = socket.accept
    data_buffer = ""

    loop do
        begin
            connection.read_nonblock(READ_CHUNK, data_buffer)
            puts "Buffer = #{data_buffer}"
        rescue Errno::EAGAIN => e
            IO.select([connection])         
            retry
        rescue EOFError
            break
        end
    end
    connection.write("HTTP/1.1 200 \r\n")
    connection.write("Content-Type: text/html\r\n")
    connection.write("Status 200 \r\n")
    connection.write("Connection: close \r\n")
    connection.write("Hello World \r\n")
    connection.close
end

我想知道Ruby服务器使用的最佳实践/标准方法.我看到Unicorn使用来自kgio库的read_nonblock而mongrel使用了readpartial(我不确定这些但是通过代码这就是我认为采用的方法.)即使检查\ r \n服务器如何知道输入完成.能解释一下这个应该怎么做(我认为gets是没有办法-与read,readpartial,read_nonblock).

2).我真的很感激如何在像独角兽或乘客这样的服务器中实现这一点

谢谢.

Sht*_*lic 5

这是在独角兽这里完成的 https://github.com/defunkt/unicorn/blob/master/lib/unicorn/http_request.rb#L69-L71

add_parse方法(阅读以上方法的评论) https://github.com/defunkt/unicorn/blob/master/ext/unicorn_http/unicorn_http.rl#L760-L778

另请参阅http://www.ruby-forum.com/topic/2267632#1014288中的一些解释

以下是使用http_parser.rb https://gist.github.com/4136962的工作代码

gem install http_parser.rb

require 'socket'
require "http/parser"


READ_CHUNK = 1024 * 4
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
addr = Socket.pack_sockaddr_in(9799, '127.0.0.1')
socket.bind(addr)
socket.listen(Socket::SOMAXCONN)
socket.setsockopt(:SOCKET, :REUSEADDR, true)

puts "Server is listening on port = 9799"
loop do
    connection, addr_info = socket.accept

    parser = Http::Parser.new
    begin
      data = connection.readpartial(READ_CHUNK)
      puts "Buffer = #{data}"
      parser << data
    end until parser.headers

    connection.write("HTTP/1.1 200 \r\n")
    connection.write("Content-Type: text/html\r\n")
    connection.write("Status 200 \r\n")
    connection.write("Connection: close \r\n")
    connection.write("\r\n\r\n")
    connection.write("Hello World \r\n")
    connection.close
end
Run Code Online (Sandbox Code Playgroud)