2012-11-23 9 views
5

Ho una domanda 2 parte sulla lettura dal socket e come viene gestito su server di Ruby come Unicorn o MongrelCome leggere da una presa TCPServer in Ruby utilizzando leggere, readpartial e read_nonblock

  1. ho imparato che leggere da un socket è diverso dalla lettura di un file e che non ci sono messaggi EOF distinti inviati e i dati sono un flusso infinito. Quindi come fai a sapere quando smettere di leggere? Il mio TCPServer per esempio in questo caso quando colpisco il mio server accedendo a http://localhost:9799 da un browser, si blocca dopo che non ci sono più dati da leggere e non getterà neanche l'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 
 

Mi piacerebbe sapere che cosa è il migliore/approccio standard pratica usata dai server Ruby. Vedo che l'Unicorn usa read_nonblock dalla libreria kgio e mongrel usa readpartial (non sono sicuro di questi, ma passando attraverso il codice questo è quello che ritengo sia l'approccio adottato). Anche con i controlli per \ r \ n come fa il server a sapere l'input è completo. Potrebbe spiegare come dovrebbe essere fatto (e penso che gets non sia l'approccio - è con read, readpartial, read_nonblock).

2). Gradirei davvero alcune righe su come ottenere questo risultato in server come unicorno o passeggero

Grazie.

risposta

5

E 'fatta in unicorno qui https://github.com/defunkt/unicorn/blob/master/lib/unicorn/http_request.rb#L69-L71

C'è add_parse metodo (leggere i commenti metodi di cui sopra) https://github.com/defunkt/unicorn/blob/master/ext/unicorn_http/unicorn_http.rl#L760-L778

prendere anche uno sguardo ad alcune spiegazioni qui http://www.ruby-forum.com/topic/2267632#1014288

Ecco il tuo codice di lavoro utilizzando 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 
+0

Grazie per la risposta e l'introduzione a http_parser.rb. Conoscere eventuali server che non utilizzano la libreria parser e optare per un altro approccio? – Sid

+0

Non conosco server che non usano parser, che tipo di un altro approccio? – Shtirlic

+0

Mi dispiace cosa intendevo dire server che non usano la libreria http_parser.rb. – Sid

Problemi correlati