2008-10-14 11 views
9

J'essaie de créer un serveur HTTP à usage unique pour gérer un seul rappel et j'ai besoin d'aide pour trouver un port TCP libre dans Ruby.Comment trouvez-vous un port de serveur TCP gratuit en utilisant Ruby?

C'est le squelette de ce que je fais:

require 'socket' 
t = STDIN.read 
port = 8081 
while s = TCPServer.new('127.0.0.1', port).accept 
    puts s.gets 
    s.print "HTTP/1.1 200/OK\rContent-type: text/plain\r\n\r\n" + t 
    s.close 
    exit 
end 

(Il fait écho entrée standard à la première connexion, puis meurt.)

Comment puis-je trouver automatiquement un port libre d'écouter sur?

Cela semble être le seul moyen de démarrer un travail sur un serveur distant qui appelle ensuite avec un ID de travail unique. Cet ID de travail peut ensuite être interrogé pour obtenir des informations sur l'état. Pourquoi les concepteurs d'origine ne pouvaient pas simplement renvoyer l'ID du travail lors de la planification du travail que je ne connaîtrai jamais. Un seul port ne peut pas être utilisé car des conflits avec plusieurs rappels peuvent se produire; de cette façon, les ports ne sont utilisés que pendant + - 5 secondes.

Répondre

-7

Je suppose que vous pourriez essayer tous les ports> 5000 (par exemple) en séquence. Mais comment allez-vous communiquer au programme client quel port vous écoutez? Il semble plus simple de décider d'un port, puis de le rendre facilement configurable, si vous avez besoin de déplacer votre script entre différents environnements.

Pour HTTP, le port standard est 80. ports alternatifs que j'ai vu utilisés sont 8080, 880 et 8000.

+0

Voir (nouveau) dernier paragraphe de la question. –

+1

Ceci ne devrait pas être la réponse acceptée; voir http://stackoverflow.com/a/201528/3528 ci-dessous. –

-6

Ne pas communiquer sur les ports aléatoires. Choisissez-en un par défaut et rendez-le configurable. Les ports aléatoires sont incompatibles avec les pare-feu. FTP fait cela et le pare-feu est un cauchemar - il doit inspecter profondément les paquets.

+3

La question était de savoir comment trouver un port gratuit à utiliser, pas si c'est une bonne idée d'utiliser un port aléatoire. – ZombieDev

+0

Tout le trafic TCP/IP ne passe pas par des pare-feu. –

3

Il est en fait assez facile quand vous ne pas essayer de tout faire en une ligne: -/

require 'socket' 
t = STDIN.read 

port = 8080 # preferred port 
begin 
    server = TCPServer.new('127.0.0.1', port)  
rescue Errno::EADDRINUSE 
    port = rand(65000 - 1024) + 1024 
    retry 
end 

# Start remote process with the value of port 

socket = server.accept 
puts socket.gets 
socket.print "HTTP/1.1 200/OK\rContent-type: text/plain\r\n\r\n" + t 
socket.close 

Ceci accomplit (mot fort) le même que l'extrait dans la question.

+4

Juste pour choisir ... Cueillir au hasard comme ceci est une boucle illimitée, et peut théoriquement fonctionner pendant une durée indéfinie sur un serveur; une situation qui s'aggrave avec le nombre de ports déjà utilisés. –

64

Transmettez 0 pour le numéro de port. Cela entraînera le système à choisir un port pour vous hors de la plage de port éphémère. Une fois que vous avez créé le serveur, vous pouvez lui demander son addr, qui contiendra le port auquel le serveur est lié.

server = TCPServer.new('127.0.0.1', 0) 
port = server.addr[1] 
+0

J'utilise un socket de base (pas TCPSocket), qui n'a pas la méthode 'addr'. Seriez-vous capable de savoir comment je peux obtenir le port dans ce cas? – troelskn

+3

En réponse à ma propre question, utilisez 'socket.getsockname.unpack (" snA * ") [1]' – troelskn