2008-09-14 8 views
7

Je lis des lignes d'entrée sur une socket TCP, semblable à ceci:Récupération d'un socket TCP cassé en Ruby quand dans 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 le point final met fin à la connexion en getline() est courir puis obtient() se bloque.

Comment puis-je contourner le problème? Est-il nécessaire de faire des E/S non bloquantes ou temporisées?

Répondre

-2

Si vous croyez le rdoc pour les douilles rubis, ils n'implémentent pas gets. Cela m'amène à croire que gets est fourni par un niveau d'abstraction plus élevé (peut-être les bibliothèques IO?) Et n'est probablement pas au courant des choses spécifiques au socket comme «connection closed».

Essayez d'utiliser recvfrom au lieu de gets

6

Vous pouvez utiliser select pour voir si vous pouvez en toute sécurité se de la prise, voir la mise en œuvre suivante d'un TCPServer en utilisant cette technique.

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 

Et voici un client qui tente de briser le serveur:

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

faute de frappe Petit là, je crois que vous vouliez: http://gist.github.com/527750 – rogerdpack

2

Le IO # fermé? renvoie vrai lorsque le lecteur et l'auteur sont fermés. Dans votre cas, @ sock.gets renvoie zéro, puis vous appelez à nouveau getcmd, et cela s'exécute dans une boucle sans fin. Vous pouvez soit utiliser select, soit fermer le socket quand gets renvoie zéro.

+0

Si la socket est fermée le reçoit pendra – QueueHammer

+0

oui si vous ajoutez une déclaration print « ici » au sein de votre boucle getcmd " – rogerdpack

0

Je recommande d'utiliser readpartial à lire à partir de votre prise et aussi attraper remet à zéro par les pairs:

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 

Ce code emprunte beaucoup à certains nice IBM code par M. Tim Jones. Notez que @server_socket est initialisé par:

@server_socket = TCPServer.open(port) 

@sockets est juste un tableau de sockets.

0

Je simplement pgrep "ruby" pour trouver le pid, et tuer -9 le pid et redémarrer.

+0

Bien que cela puisse être une solution de contournement pratique à court terme, il ne résout pas le problème sous-jacent. –

Questions connexes