2010-06-02 8 views
12

Sto provando a connettermi, leggere e scrivere da un socket UNIX in Ruby. È una presa di stats usata da haproxy.Lettura/scrittura da un socket Unix in Ruby

Il mio codice è il seguente:

require 'socket' 
socket = UNIXSocket.new("/tmp/haproxy.stats.socket") 

# First attempt: works 

socket.puts("show stat") 

while(line = socket.gets) do 
    puts line 
end 

# Second attemp: fails 

socket.puts("show stat") 

while(line = socket.gets) do 
    puts line 
end 

Riesce la prima volta, ma al secondo tentativo fallisce. Non sono sicuro del perché.

# pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt, 
stats,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,1,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,, 
stats,BACKEND,0,0,0,0,2000,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,0,22,0,,1,1,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0, 
legacy_socket,FRONTEND,,,0,0,1000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,2,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,, 
all,FRONTEND,,,0,0,10000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,3,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,22,22,,1,4,1,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,22,22,,1,4,2,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,22,22,,1,4,3,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,22,22,,1,4,4,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,22,22,,1,4,5,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,22,22,,1,4,6,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,22,22,,1,4,7,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,21,21,,1,4,8,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,21,21,,1,4,9,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,socket,0,0,0,0,200,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,21,21,,1,4,10,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
socket_backend,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,DOWN,0,0,0,,1,21,21,,1,4,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0, 
api_backend,api,0,0,0,0,200,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,0,22,0,,1,5,1,,0,,2,0,,0,L4OK,,0,0,0,0,0,0,0,0,,,,0,0, 
api_backend,api,0,0,0,0,1,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,0,22,0,,1,5,2,,0,,2,0,,0,L4OK,,0,0,0,0,0,0,0,0,,,,0,0, 
api_backend,api,0,0,0,0,1,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,21,21,,1,5,3,,0,,2,0,,0,L4CON,,0,0,0,0,0,0,0,0,,,,0,0, 
api_backend,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,UP,2,2,0,,0,22,0,,1,5,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0, 
www_backend,ruby-www,0,0,0,0,10000,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,0,22,0,,1,6,1,,0,,2,0,,0,L4OK,,0,0,0,0,0,0,0,0,,,,0,0, 
www_backend,BACKEND,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,UP,1,1,0,,0,22,0,,1,6,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0, 

/Users/Olly/Desktop/haproxy_stats.rb:14:in `write': Broken pipe (Errno::EPIPE) 
    from /Users/Olly/Desktop/haproxy_stats.rb:14:in `puts' 
    from /Users/Olly/Desktop/haproxy_stats.rb:14 

Qual è il problema? C'è un buon riferimento all'uso dei socket UNIX e di Ruby?

risposta

5

Sembra che la connessione sia stata chiusa dopo la prima richiesta. Non penso che tu stia facendo qualcosa di sbagliato. Il socket delle statistiche HAProxy è probabilmente progettato in modo che risponda a un singolo comando e quindi chiuda la connessione.

Penso che sia necessario riconnettersi per ogni richiesta.

Se si guarda a this blog post che è sull'utilizzo HAProxy presa di statistiche con socat allora questo ha un senso perchè si reindirizza il comando show stat in socat e socat legge dalla presa fino a che non si chiude.

+0

Grazie. Sembra che ho bisogno di leggere su come funzionano i socket UNIX. Mi aspettavo che funzionasse come un TCPSocket rimasto aperto. – Olly

+0

Una delle cose che non ottengo è quando uso socat, quindi ottengo SEMPRE i risultati restituiti dal socket, tuttavia quando faccio questo tramite il codice ruby ​​sopra, ogni tanto non ottengo alcun dato restituito da HAproxy ... quindi devo correre più volte ... alcuni aspetti poco chiari nell'implementazione del socket di Ruby credo. – gyre

0

È possibile utilizzare la presa uomo. Puoi usare la classe socket proprio come faresti se fosse una funzione C.

Ho trovato pagine di manuale molto utili.

13

Olly,

HAproxy chiude la connessione dopo la prima richiesta a meno che non si utilizza il comando "prompt" (vedi http://haproxy.1wt.eu/download/1.4/doc/configuration.txt la sezione 9.2):

#!/usr/bin/env ruby                               

require 'socket'                                

socket = UNIXSocket.new("/tmp/haproxy.stats.socket")                        

# Goes interactive mode 
socket.puts("prompt")                              

# Ask statistics every second                                
while true                                 
    socket.puts("show stat")                             
    socket.each_char do |c| 
    # We had the prompt, break out                         
    break if c == '>'                              
    print c                                 
    end                                  

    sleep 1                                 
end    
2

Ho anche incontrato lo stesso problema quando uso socket.puts, è possibile utilizzare socket.write anziché socket.puts per risolvere il problema.

#!/usr/bin/evn ruby 
# -*- coding: UTF-8 -*- 

require 'rubygems' 
require 'uri' 
require 'socket' 
require 'yaml' 

SOCKET = URI.parse("/var/run/haproxy/haproxy.sock") 

def get_info 
    UNIXSocket.open(SOCKET.path) do |socket| 
    socket.write("show info;") 
    info = YAML::load socket 
    #info.each {|key, value| puts "#{key} ➤ #{value}"} 
    end 
end 

puts get_info["Uptime_sec"] 

Guardate questo gem per ulteriori informazioni, il codice sorgente è here.