塊I具有用於Ruby的一個簡單的TCP服務器下面的代碼:Socket.read()將不會在紅寶石
# 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