在gets()中从Ruby中的TCP套接字恢复

时间:2008-09-14 21:53:57

标签: ruby sockets tcp gets

我正在读取TCP套接字上的输入行,类似于:

class Bla  
  def getcmd
    @sock.gets unless @sock.closed?
  end

  def start     
    srv = TCPServer.new(5000)
    @sock = srv.accept
    while ! @sock.closed?
      ans = getcmd
    end
  end
end

如果端点在getline()运行时终止连接,则gets()挂起。

我该如何解决这个问题?是否有必要进行非阻塞或定时I / O?

5 个答案:

答案 0 :(得分:7)

您可以使用select查看是否可以安全地从套接字获取,请参阅以下使用此技术实现TCPServer。

require 'socket'

host, port = 'localhost', 7000

TCPServer.open(host, port) do |server|
  while client = server.accept
    readfds = true
    got = nil
    begin
      readfds, writefds, exceptfds = select([client], nil, nil, 0.1)
      p :r => readfds, :w => writefds, :e => exceptfds

      if readfds
        got = client.gets 
        p got
      end
    end while got
  end
end

这是一个试图打破服务器的客户端:

require 'socket'

host, port = 'localhost', 7000

TCPSocket.open(host, port) do |socket|
  socket.puts "Hey there"
  socket.write 'he'
  socket.flush
  socket.close
end

答案 1 :(得分:2)

IO#关闭了吗?当读取器和写入器都关闭时返回true。 在你的情况下,@ sock.gets返回nil,然后再次调用getcmd,这将在一个永无止境的循环中运行。您可以使用select,也可以在获取返回nil时关闭套接字。

答案 2 :(得分:0)

我建议使用readpartial从套接字读取并捕获对等重置:

while true
    sockets_ready = select(@sockets, nil, nil, nil)
    if sockets_ready != nil
      sockets_ready[0].each do |socket|
        begin
          if (socket == @server_socket)
            # puts "Connection accepted!"
            @sockets << @server_socket.accept
          else
            # Received something on a client socket
            if socket.eof?
              # puts "Disconnect!"
              socket.close
              @sockets.delete(socket)
            else
              data = ""
              recv_length = 256
              while (tmp = socket.readpartial(recv_length))
                data += tmp
                break if (!socket.ready?)
              end
              listen socket, data
            end
          end
        rescue Exception => exception
          case exception
            when Errno::ECONNRESET,Errno::ECONNABORTED,Errno::ETIMEDOUT
              # puts "Socket: #{exception.class}"
              @sockets.delete(socket)
            else
              raise exception
          end
        end
      end
    end
  end

这段代码大量借用了M. Tim Jones的一些nice IBM code。请注意,@ server_socket由以下内容初始化:

@server_socket = TCPServer.open(port)

@sockets只是一个套接字数组。

答案 3 :(得分:0)

我只是pgrep“ruby”找到pid,然后杀掉-9 pid并重启。

答案 4 :(得分:-2)

如果你相信ruby套接字的rdoc,它们就不会实现gets。这让我相信get是由更高级别的抽象(可能是IO库?)提供的,并且可能不知道特定于套接字的东西,比如'连接已关闭'。

尝试使用recvfrom代替gets