繁体   English   中英

从Ruby中的TCPSocket读取

[英]Reading from a TCPSocket in Ruby

此代码将两个HTTP请求发送到www.example.com网站:

require 'socket'

@host = 'www.example.com'
@port = 80
@path = "/"

# Build HTTP request
def request(close=false)
  "GET #{@path} HTTP/1.1\r\nHost: #{@host}#{"\r\nConnection: close" if close}\r\n\r\n"
end

# Build socket
socket = TCPSocket.open(@host,@port)  # Connect to server

# Send request twice via socket
2.times {socket.print request}

我找到了以下各种读取响应的方法:

# Method 1: close_write and read
socket.close_write # Without this line, the next line hangs
response = socket.read
puts response.length

# Method 2: send another http request with 'Connection: close' header, then use 'read'
socket.print request(true) # Without this line, the next line hangs
response = socket.read
puts response.length

# Method 3: recv
# puts socket.eof?  # Method fails when I add this line
r1, r2 = socket.recv(1000000), socket.recv(1000000)
puts r1.length, r2.length

# Method 4: IO.select and read_nonblock
puts socket.eof?
# IO.select([socket])  # The code still works without this IO.select...
r1 = socket.read_nonblock(9999999)
IO.select([socket])  # ...but not without this one
r2 = socket.read_nonblock(9999999)
puts r1.length, r2.length
puts socket.eof? # Hangs for ages before returning 'true'

问题:

  1. 方法1中的'socket.close_write'行到底是做什么的,为什么该方法必须起作用?
  2. 在方法2中,“ Connection:close”标头是否以某种方式获得与方法1中“ socket.close_write”行相同的结果? 如果不是,它在做什么,为什么其余的方法必须起作用?
  3. 为什么在方法3中添加注释行“ puts socket.eof?”会导致其余代码挂起?
  4. 在方法3中,recv调用如何以及为什么在HTTP响应结束时停止(而不是也选择下一个响应)?
  5. 为什么方法4中的第二个IO.select是必需的,但第一个不是必需的?
  6. IO.select实际做什么?
  7. 为什么方法4中的最后一行“ puts socket.eof?”在返回true之前会挂起一段时间?
  8. 有没有一种通用的方法来检查套接字当前期望多少个响应,并从套接字读取该数目的响应,而无需关闭套接字进行写入?

最后,如果这里不可能提供答案,那么是否有足够的资源可以使我对上述所有内容有所了解,并且可以从读取TCP套接字(或一般来说是网络套接字)中获得大致的了解?

谢谢。

不需要socket.close_write 我的意思是,您可以通过socket.read获得套接字返回的socket.read ,但是您将要等待一段时间。 原因是因为您试图使用socket.read读取整个流。 这需要时间。 您可以通过执行以下操作来找出套接字返回的内容:

socket.each_line do |line|
  puts line
end

顺便说一句, Nagle的算法也使它变慢。

close_write作用是让客户端半关闭套接字,当服务器端注意到这一点时,它也将关闭它的一侧。 然后,您可以非常快速地完成阅读。

或者您可以使用IO::select 。如文档所述:

它监视给定的IO对象数组,等待一个或多个IO对象准备好读取,准备好写入并分别具有待处理的异常,并返回包含这些IO对象的数组的数组。 如果给出了可选的超时值,并且在超时秒数内没有IO对象准备就绪,它将返回nil。

ready = IO.select([socket], nil, nil, 10)
if ready
  # do something
else
  # raise timeout
end

在这里,我们传递第一个参数,它是ready for reading的对象,最后一个是您要设置的超时。 这意味着,如果10秒钟后仍未准备好读数,它将返回nil,然后引发超时错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM