【问题标题】:Reading / Writing from a Unix Socket in Ruby从 Ruby 中的 Unix 套接字读取/写入
【发布时间】:2010-06-02 16:54:44
【问题描述】:

我正在尝试从 Ruby 中的 UNIX 套接字进行连接、读取和写入。它是 haproxy 使用的统计套接字。

我的代码如下:

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

第一次成功,第二次失败。我不知道为什么。

# 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

有什么问题?有没有关于使用 UNIX 套接字和 Ruby 的好的参考资料?

【问题讨论】:

    标签: ruby unix-socket


    【解决方案1】:

    奥利,

    HAproxy 在第一次请求后关闭连接,除非您使用“提示”命令(参见http://haproxy.1wt.eu/download/1.4/doc/configuration.txt 第 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】:

      看起来连接在第一次请求后已关闭。我不认为你做错了什么。 HAProxy stats socket 可能被设计成响应单个命令然后关闭连接。

      我认为您需要为每个请求重新连接。

      如果您查看this blog post,它是关于将 HAProxy stats socket 与 socat 结合使用,那么这是有道理的,因为您将 show stat 命令通过管道传输到 socat 并且 socat 从套接字读取直到它关闭。

      【讨论】:

      • 谢谢。看起来我需要了解 UNIX 套接字是如何工作的。我期待它能够像 TCPSocket 一样保持打开状态。
      • 我没有得到的一件事是当我使用 socat 时,我总是得到从套接字返回的结果,但是当我通过上面的 ruby​​ 代码执行此操作时,我时不时地没有从 HAproxy 返回任何数据......所以我必须运行几次......我猜 Ruby 的套接字实现中有一些狡猾的东西。
      【解决方案3】:

      我在使用socket.puts的时候也遇到了同样的问题,你可以用socket.write代替socket.puts来解决。

      #!/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"]
      

      查看这个gem了解更多信息,源代码是here

      【讨论】:

        【解决方案4】:

        你可以使用 man socket。您可以像使用 C 函数一样使用套接字类。

        我发现手册页非常有用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-09-30
          • 1970-01-01
          • 2011-12-06
          • 2017-07-31
          • 2014-11-04
          • 2019-02-23
          • 1970-01-01
          相关资源
          最近更新 更多