7

次のような 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 を行う必要がありますか?

4

5 に答える 5

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
于 2008-09-15T16:13:31.390 に答える
2

IO#closed? リーダーとライターの両方が閉じている場合は true を返します。あなたの場合、@sock.gets は nil を返し、次に getcmd を再度呼び出すと、これは終わりのないループで実行されます。select を使用するか、gets が nil を返したときにソケットを閉じることができます。

于 2008-09-18T12:54:45.773 に答える
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 による優れた IBM コードから大いに借用しています。@server_socket は次のように初期化されることに注意してください。

@server_socket = TCPServer.open(port)

@sockets は単なるソケットの配列です。

于 2011-05-15T00:56:04.103 に答える
0

「ruby」をpgrepしてpidを見つけ、pidを-9でkillして再起動するだけです。

于 2016-03-18T04:55:03.977 に答える
-2

ruby ソケットのrdocを信じるなら、それらは実装していませんgets。これにより、より高いレベルの抽象化 (おそらく IO ライブラリ?) によって get が提供され、おそらく「接続が閉じられた」などのソケット固有のものを認識していないと思います。

recvfromの代わりに使用してみてくださいgets

于 2008-09-14T23:51:04.357 に答える