Recuperarse de un socket TCP roto en Ruby cuando está en get()
sockets gets (5)
Si crees que el rdoc para los zócalos de rubí, no implementa get . 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''.
Intenta usar recvfrom
lugar de gets
Estoy leyendo líneas de entrada en un socket TCP, similar a esto:
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 extremo finaliza la conexión mientras getline () se está ejecutando, gets () se cuelga.
¿Cómo puedo solucionar esto? ¿Es necesario hacer E / S sin bloqueo o temporizadas?
¿El IO # cerrado? devuelve verdadero cuando tanto el lector como el escritor están cerrados. En su caso, @eck.gets devuelve nil, y luego llama al getcmd nuevamente, y esto se ejecuta en un ciclo interminable. Puede usar select o cerrar el socket cuando obtiene return nil.
Puede usar seleccionar para ver si puede obtener de manera segura desde el socket; consulte la siguiente implementación de un TCPServer utilizando 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
Recomiendo usar readpartial para leer desde su socket y también detectar reinicios entre iguales:
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 toma prestado en gran medida de un buen código de IBM por M. Tim Jones. Tenga en cuenta que @server_socket está inicializado por:
@server_socket = TCPServer.open(port)
@sockets es solo una variedad de sockets.
Simplemente pgrep "ruby" para encontrar el pid, y matar -9 el pid y reiniciar.