にブロックされません。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.read
のserver.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)
EOFでブロックする方法があるかどうかは分かりますか?私はシンプルなチャットサーバーとクライアントを実装して遊んでいますが、クライアントとサーバーの間に長時間の接続があることを期待していました。私が最後に望むのは、サーバーが100%CPUに移動し、ほとんどの場合、データを持たないソケットを積極的にループすることです。 – Reck
とにかくこれらの接続を検出して削除する必要があるため、それらの接続をスキップしたくない場合があります。データがない(まだ他端に接続されている)ソケットとEOFのソケット(切断されていて、それを閉じるだけで済むソケット)には違いがあることに注意してください。 – matt
あなたは絶対に正しいです! – Reck