2008-09-14 3 views
7

Ich Eingabezeilen auf einem TCP-Socket, ähnlich wie bei der Lektüre dieses:von einem gebrochenen TCP-Socket in Ruby Wiederherstellen, wenn in 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 

Wenn der Endpunkt beendet die Verbindung während getline() ist läuft dann wird gets() hängt.

Wie kann ich das umgehen? Müssen nicht blockierende oder zeitgesteuerte E/A durchgeführt werden?

Antwort

-2

Wenn Sie die rdoc für Ruby-Sockets glauben, implementieren sie gets nicht. Dies führt mich zu der Annahme, dass die gets von einem höheren Abstraktionsniveau (vielleicht die IO-Bibliotheken?) Zur Verfügung gestellt wird und wahrscheinlich nicht wissen Socket-spezifische Dinge wie "Verbindung geschlossen."

Versuchen Sie es mit recvfrom statt gets

6

Sie wählen können, um zu sehen, ob Sie können sicher aus der Steckdose kommt, siehe nachfolgende Implementierung eines TCPServer mit dieser Technik.

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 

Und hier ein Client, den Server zu brechen versucht:

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

Kleiner Tippfehler drin, ich glaube, Sie wollten: http://gist.github.com/527750 – rogerdpack

2

Die IO # geschlossen? gibt true zurück, wenn sowohl der Reader als auch der Writer geschlossen sind. In Ihrem Fall gibt das @ sock.gets nil zurück, und Sie rufen das getcmd erneut auf, und das wird in einer nie endenden Schleife ausgeführt. Sie können entweder select verwenden oder den Socket schließen, wenn gets nil zurückgibt.

+0

Wenn der Socket geschlossen ist das bekommt – QueueHammer

+0

hängen ja wenn Sie einen Druck hinzufügen ‚hier‘ Anweisung in Ihrer getcmd Schleife Sie werden sehen, dass es für immer looping ist. Lesen Sie dazu "" – rogerdpack

0

ich empfehlen die Verwendung von readpartial aus Ihrer Steckdose zu lesen und auch Peer-Resets zu kontrollieren:

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 

Dieser Code lehnt sich stark von einigen nice IBM code von M. Tim Jones. Beachten Sie, dass @server_socket initialisiert wird durch:

@server_socket = TCPServer.open(port) 

@ Sockets ist nur ein Array von Sockets.

0

Ich einfach pgrep "Ruby", um die PID zu finden, und töten -9 die PID und neu starten.

+0

Dies kann zwar eine praktische kurzfristige Abhilfe sein, behebt jedoch nicht das zugrunde liegende Problem. –