2008-10-23 4 views
19

Comment définir le délai d'attente pour les opérations de blocage sur une socket Ruby?Comment définir le délai d'attente de socket dans Ruby?

+2

Trouvé une bien meilleure solution que votre accepté ici: http://stackoverflow.com/a/12111120/216314 –

+0

http://ruby-doc.org/stdlib/libdoc/timeout/rdoc/Timeout.html –

+0

[Module de temporisation avec verrous exclusifs] (http://stackoverflow.com/a/15304835/1301972). –

Répondre

17

La solution que je trouve qui semble fonctionner est d'utiliser Timeout::timeout:

require 'timeout' 
    ... 
begin 
    timeout(5) do 
     message, client_address = some_socket.recvfrom(1024) 
    end 
rescue Timeout::Error 
    puts "Timed out!" 
end 
+13

L'utilisation du délai d'attente est une erreur. En raison des theards verts, tout ce qui bloque sur IO bloquera également le thread du timeout, l'empêchant ainsi de fonctionner. – Sardathrion

+0

@Sardathrion, merci pour les commentaires, mais une solution serait mieux qu'un commentaire négatif :) – Mike

+1

Les fils de rubis sont cassés j'ai peur. Trouver une meilleure langue - dure mais vraie. – Sardathrion

15

L'objet de délai d'attente est une bonne solution.

Voici un exemple d'E/S asynchrones (non-bloquant dans la nature et se produit de manière asynchrone à le flux de l'application.)

IO.select(read_array 
[, write_array 
[, error_array 
[, timeout]]]) => array or nil 

Peut être utilisé pour obtenir le même effet.

require 'socket' 

strmSock1 = TCPSocket::new("www.dn.se", 80) 
strmSock2 = TCPSocket::new("www.svd.se", 80) 
# Block until one or more events are received 
#result = select([strmSock1, strmSock2, STDIN], nil, nil) 
timeout=5 

timeout=100 
result = select([strmSock1, strmSock2], nil, nil,timeout) 
puts result.inspect 
if result 

    for inp in result[0] 
    if inp == strmSock1 then 
     # data avail on strmSock1 
     puts "data avail on strmSock1" 
    elsif inp == strmSock2 then 
     # data avail on strmSock2 
     puts "data avail on strmSock2" 
    elsif inp == STDIN 
     # data avail on STDIN 
     puts "data avail on STDIN" 
    end 
    end 
end 
8

Je pense que l'approche non bloquante est la voie à suivre.
J'ai essayé l'article mentionné ci-dessus et je pouvais toujours l'accrocher.
cet article non blocking networking et l'approche de jonke ci-dessus m'a mis sur la bonne voie. Mon serveur bloquait sur la connexion initiale donc j'avais besoin d'être un peu plus bas niveau.
la prise rdoc peut donner plus de détails dans le connect_nonblock

def self.open(host, port, timeout=10) 
addr = Socket.getaddrinfo(host, nil) 
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0) 

begin 
    sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3])) 
rescue Errno::EINPROGRESS 
    resp = IO.select([sock],nil, nil, timeout.to_i) 
    if resp.nil? 
    raise Errno::ECONNREFUSED 
    end 
    begin 
    sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3])) 
    rescue Errno::EISCONN 
    end 
end 
sock 
end 

pour obtenir un bon test. Démarrez un serveur de socket simple, puis effectuez un ctrl-z pour l'arrière-plan

Le paramètre IO.select attend des données sur le flux d'entrée dans les 10 secondes. cela peut ne pas fonctionner si ce n'est pas le cas.

Il devrait être un bon remplacement de la méthode ouverte de TCPSocket.

+0

Cela fonctionne très bien pour moi. Timeout ne doit en aucun cas être utilisé en raison des threads verts de MRI. – Sardathrion

+2

Une connexion non bloquante est accessible en écriture lorsqu'elle est prête. Utilisez 'IO.select (nil, [sock], nil, timeout.to_i)' – tmm1

+0

Seulement travaillé pour moi après avoir utilisé le commentaire de tmm1. –

Questions connexes