对于Ruby中的简单TCP服务器,我有以下代码:
# 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)
答案 0 :(得分:1)
read
将阻止,但在EOF时不会阻止。 IO#read
docs say:
在文件末尾调用此方法时,它会返回
nil
或""
,具体取决于长度:read
,read(nil)
,并read(0)
返回""
,read(positive_integer)
返回nil
。
由于在EOF上调用read
没有阻止,select
会立即将IO返回。
在您的代码中,对read
的第一次调用将阻塞,直到 all 从连接中读取数据(即另一端已关闭它)。从那时起它将在EOF,因此select
会将其恢复为准备状态,read
将立即返回一个空字符串。