2008-09-14 10 views
7

estoy leyendo las líneas de entrada en un socket TCP, similar a esto:Para recuperarse de un socket TCP rota en Ruby, cuando en gets()

class Bla 
    def getcmd 
    @sock.gets unless @sock.closed? 
    end 

    def start  
    srv = TCPServer.new(5000) 
    @sock = srv.accept 
    while ! @sock.closed? 
     ans = getcmd 
    end 
    end 
end 

Si el punto final termina la conexión mientras getline() es corriendo se pone() se bloquea.

¿Cómo puedo evitar esto? ¿Es necesario hacer E/S sin bloqueo o temporizadas?

Respuesta

-2

Si cree que el rdoc para conectores de rubí, no implementa gets. Esto me lleva a pensar que get está siendo proporcionado por un nivel más alto de abstracción (¿tal vez las bibliotecas IO?) Y probablemente no esté al tanto de cosas específicas del socket como 'connection closed'.

Intente utilizar recvfrom en lugar de gets

6

puede utilizar Select para ver si se puede con seguridad de la toma, ver tras la aplicación de un TCPServer uso de esta técnica.

require 'socket' 

host, port = 'localhost', 7000 

TCPServer.open(host, port) do |server| 
    while client = server.accept 
    readfds = true 
    got = nil 
    begin 
     readfds, writefds, exceptfds = select([client], nil, nil, 0.1) 
     p :r => readfds, :w => writefds, :e => exceptfds 

     if readfds 
     got = client.gets 
     p got 
     end 
    end while got 
    end 
end 

Y aquí un cliente que intenta romper el servidor:

require 'socket' 

host, port = 'localhost', 7000 

TCPSocket.open(host, port) do |socket| 
    socket.puts "Hey there" 
    socket.write 'he' 
    socket.flush 
    socket.close 
end 
+0

pequeña errata en allí, creo que quería: http://gist.github.com/527750 – rogerdpack

2

El IO # cerrada? devuelve verdadero cuando tanto el lector como el escritor están cerrados. En su caso, @eck.gets devuelve nil, y luego llama de nuevo al getcmd, y esto se ejecuta en un ciclo interminable. Puede usar select o cerrar el socket cuando obtiene return nil.

+0

Si el socket está cerrado el se va a colgar – QueueHammer

+0

sí si se agrega una impresión 'aquí' declaración dentro de su bucle getcmd Verá que está girando para siempre, leyendo "" – rogerdpack

0

recomiendo el uso de readpartial para leer desde su toma de corriente y también la captura de restablecimientos de pares:

while true 
    sockets_ready = select(@sockets, nil, nil, nil) 
    if sockets_ready != nil 
     sockets_ready[0].each do |socket| 
     begin 
      if (socket == @server_socket) 
      # puts "Connection accepted!" 
      @sockets << @server_socket.accept 
      else 
      # Received something on a client socket 
      if socket.eof? 
       # puts "Disconnect!" 
       socket.close 
       @sockets.delete(socket) 
      else 
       data = "" 
       recv_length = 256 
       while (tmp = socket.readpartial(recv_length)) 
       data += tmp 
       break if (!socket.ready?) 
       end 
       listen socket, data 
      end 
      end 
     rescue Exception => exception 
      case exception 
      when Errno::ECONNRESET,Errno::ECONNABORTED,Errno::ETIMEDOUT 
       # puts "Socket: #{exception.class}" 
       @sockets.delete(socket) 
      else 
       raise exception 
      end 
     end 
     end 
    end 
    end 

Este código inspira en gran medida de algunos nice IBM code por M. Tim Jones. Tenga en cuenta que @server_socket se inicializa por:

@server_socket = TCPServer.open(port) 

@sockets es solo una matriz de sockets.

0

Simplemente pgrep "ruby" para encontrar el pid, y matar -9 el pid y reiniciar.

+0

Si bien esto puede ser una solución práctica a corto plazo, no soluciona el problema subyacente. –

Cuestiones relacionadas