新手问题 Ruby 多线程问题

itzzq · 2014年03月12日 · 最后由 itzzq 回复于 2014年03月12日 · 3376 次阅读

大家好,首次发帖呀。最近在苦修 Ruby,刚好需要记录好几台机器的内存信息,就写了个 socket 程序,基本功能是实现了,但是还是有点问题想破脑壳……智商不够用啊……程序是这样的: 首先开始服务端 server,然后开启客户端 client,建立连接之后 server 发送 start,每台机器的 client 开始发送信息到 server。最后记录完毕,server 发送 stop 关闭 socket。

server:

require 'socket'

# This method expects a socket connected to a client.
# It reads the logs from the client and control the client(start or stop).
# Multiple threads may run this method at the same time.

def handle_client(c, cmd)
    command = cmd
    # Connection feekback
    c.puts "Log service running on #{Socket.gethostname}"
    c.flush 
    puts "Accepted connection from #{c.peeraddr[2]}"
    c.puts command

    while true
        remsg = c.gets.chop
        puts "#{c.peeraddr[2]}: #{remsg}"   # Main work
        c.puts command                      # Control the client
        c.flush
        break if command == "stop"
    end 
    c.close
end

server = TCPServer.open(2000)
cmd = ""
# Wait for the command 
cmdThread = Thread.new do
    loop do
        cmd = STDIN.gets.chop
        if cmd == "stop"
            break
        elsif cmd == "start"
            STDOUT.puts "Log service start!"
        else
            STDOUT.puts "Unreasonable command!"
        end
    end
end

while true  
    if cmd == "start" || cmd == "stop"
        client = server.accept
        puts "Client connected. CMD: #{cmd}."
        Thread.start(client) do |c|
            handle_client(c, cmd)
        end
    end
end

client:

require 'socket'

host, port = ARGV
interval = 1

begin
    # Give the user some feedback while connecting.
    STDOUT.print "Connecting..."
    STDOUT.flush
    s = TCPSocket.open(host, port)
    STDOUT.puts "done"

    # Now display information about the connection
    local, peer = s.addr, s.peeraddr
    STDOUT.print "Connected to #{peer[2]}:#{peer[1]}"
    STDOUT.puts " using local port #{local[1]}"

    msg = s.gets
    STDOUT.puts msg.chop            # And display it


    # Waiting the "start" command from server.
    loop do
        STDOUT.puts "Waiting the commands from server."
        msg = s.gets.chop
        STDOUT.puts "Server Command: #{msg}." 
        if msg == "start"
            break
        else
            STDOUT.puts "Unreasonable commands!"
        end
    end

    # Now begin a loop of client/server interaction.
    loop do
        STDOUT.print '> '
        STDOUT.flush

        meminfo = `free`.split "\n"

        memused = meminfo[2].split[2].to_f
        memtotal = meminfo[1].split[1].to_f
        memcost = (memused / memtotal).round(4)

        STDOUT.puts "#{Time.new} MemCost: #{memcost}"
        s.puts(memcost)            # Send the logs to the server
        s.flush

        # Read the server's response and print out.
        # The server may send more than one line, so use readpartial
        # to read whatever it sends (as long as it all arrives in one chunk).
        response = s.readpartial(4096)
        break if response.chop == "stop"
        sleep(interval)
    end

rescue              # If anything goes wrong
    puts $!         # Display the exception to the user
ensure
    s.close if s
end

现在的问题是,server 发送 start 没问题,可是发送不了 stop……求大牛拯救!

咦?怎么后面的代码变绿了……

start 以后另外一个线程里跑了 handle_client,把 cmd 传过去了(那时是 start),后面改的 stop 对他没影响啊。

#2 楼 @kenshin54 对哦!那怎么把 stop 又传过去呢?

#2 楼 @kenshin54 哈,我解决啦~我把 handle_client 的内容搬出来了,感谢你的提醒!

#1 楼 @itzzq 被理解为正则表达式了吧

#5 楼 @ShiningRay 哈,我 F12 看了一下还真是~

问题在

memcost = (meminfo[2].split[2].to_f / meminfo[1].split[1].to_f).round(4)

把那段代码写成这样就好了

memused = meminfo[2].split[2].to_f
memtotal = meminfo[1].split[1].to_f
memcost = (memused / memtotal).round(4)

与其说 start 和 stop 是命令,不如说是状态,如果命令一多的话会不会很乱。控制台与显示数据混在一起也不好。

#8 楼 @5swords 谢谢回复哈,之所以需要 start 和 stop,是因为有多台机器 client 连接 server 的时候可以让 server 统一命令同时让 client 发 log 给 server。至于控制台和显示数据混在一起是方便编程而已,后面我会把显示数据写到文件当中去,这就没有这个问题了。

#4 楼 @itzzq 能详细点说明吗?谢谢

#10 楼 @zhangsm 就是说不要 handle_client 了,直接把里面的代码放到 Tread_start 下面。不过这还不算是完美解决问题,虽然可以让 client 停止工作了,但是 server 却还是卡在那里,需要 ctrl+c 来结束掉……

#11 楼 @itzzq 嗯嗯,而且当 client 重新启动后也无法在于 server 建立连接了。

#12 楼 @zhangsm 我也不知道怎么修改……

需要 登录 后方可回复, 如果你还没有账号请 注册新账号