2017-11-11 9 views
1

にブロックされません。Socket.readは()私はRubyで簡単なTCPサーバーに対して次のコードを持っているRubyの

# server.rb 
require 'socket' 

class Server 
    def initialize(port) 
    @port = port 
    end 

    def run 
    Socket.tcp_server_loop(@port) do |connection| 
     Thread.new do 
     loop do 
      puts "IO: #{IO.select([connection]).inspect} - data: #{connection.read}" 
     end 
     end 
    end 
    end 
end 

server = Server.new(16451) 
server.run 

と同様に、この些細なTCPクライアントコード:

# client.rb 
require 'socket' 

client = TCPSocket.new('localhost', 16451) 
client.write('stuff') 

ソケットにデータが存在しない場合、connection.readserver.rbがブロックされるはずです。私は私のMacBook(OS X 10.12.5)でこれを実行したときしかし、それは次のように出力を吐き続ける:

IO: [[#<Socket:fd 12>], [], []] - data: stuff 
IO: [[#<Socket:fd 12>], [], []] - data: 
IO: [[#<Socket:fd 12>], [], []] - data: 
IO: [[#<Socket:fd 12>], [], []] - data: 
IO: [[#<Socket:fd 12>], [], []] - data: 
IO: [[#<Socket:fd 12>], [], []] - data: 
IO: [[#<Socket:fd 12>], [], []] - data: 
IO: [[#<Socket:fd 12>], [], []] - data: 
... 

このような一方でIO.selectは、ソケット上で読み取り可能なデータがあると考えているようですデータが送信されました。

Rubyでソケットを操作するときにブロックを読み取るにはどうすればよいですか?私は何か見落としていますか?


マットの答えが正しい方向に私を指摘しました。将来の読者には、私の新しいコードがあります。

# server.rb 
require 'socket' 

class Server 
    BYTESIZE_OF_PACKED_INTEGER = [1].pack('i').bytesize 

    def initialize(port) 
    @port = port 
    end 

    def run 
    Socket.tcp_server_loop(@port) do |connection| 
     Thread.new do 
     while packed_msg_bytesize = connection.read(BYTESIZE_OF_PACKED_INTEGER) 
      msg_bytesize = packed_msg_bytesize.unpack('i').first 
      msg = connection.read(msg_bytesize) 
      puts msg 
     end 
     end 
    end 
    end 
end 

server = Server.new(16451) 
server.run 

クライアントコード。

# client.rb 
require 'socket' 

msg = 'stuff' 
msg_bytesize = msg.bytesize 
packed_msg_bytesize = [msg_bytesize].pack('i') 

client = TCPSocket.new('localhost', 16451) 
client.write(packed_msg_bytesize) 
client.write(msg) 

答えて

1

readデータがない場合はブロックされますが、EOFではブロックされません。 IO#read docs sayreadread(nil)、及びread(0)リターン""read(positive_integer)戻りnil:この方法は、ファイルの最後に呼び出され

は、それがnil又は""に応じて返します。

EOFでreadを呼び出してもブロックされないため、selectはIOを直ぐに読み取り可能に返します。

readへの最初の呼び出しは、すべてまでデータが読み取られる(つまり、もう一方の端が閉じた)までブロックされます。それ以降はEOFになるので、selectはそれを準備完了として返し、readはすぐに空の文字列を返します。

+0

EOFでブロックする方法があるかどうかは分かりますか?私はシンプルなチャットサーバーとクライアントを実装して遊んでいますが、クライアントとサーバーの間に長時間の接続があることを期待していました。私が最後に望むのは、サーバーが100%CPUに移動し、ほとんどの場合、データを持たないソケットを積極的にループすることです。 – Reck

+0

とにかくこれらの接続を検出して削除する必要があるため、それらの接続をスキップしたくない場合があります。データがない(まだ他端に接続されている)ソケットとEOFのソケット(切断されていて、それを閉じるだけで済むソケット)には違いがあることに注意してください。 – matt

+0

あなたは絶対に正しいです! – Reck

関連する問題