此代码向www.example.com网站发送两个HTTP请求:
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'
问题:
- socket.close_write行在方法1中到底做了什么,为什么这个方法必须工作?
1.在方法2中,是“连接:close'头以某种方式实现了与方法1中的'socket.close_write'行相同的结果?如果不是,它在做什么,为什么方法的其余部分必须工作?
1.为什么在方法3中,添加注解行'putsocket.eof?',导致代码的其余部分挂起?
1.在方法3中,recv调用如何以及为什么在HTTP响应结束时停止(而不是同时拾取下一个响应)?
1.为什么方法4中的第二个IO.select是必要的,而第一个不是?
1.IO.select实际上是做什么的?
1.为什么最后一行'放入socket.eof?',在方法4中挂起很长时间才返回true?
1.有没有一种通用的方法来检查套接字当前期望的响应数量,并从套接字中阅读该数量的响应,而无需关闭套接字进行写入?
最后,如果在这里的答案是不可能的,有没有一个好的资源,我可以得到一些清晰的所有上述内容,并从TCP套接字(或一般网络套接字)阅读一般清晰?
1条答案
按热度按时间mu0hgdu01#
socket.close_write
不是必需的。我的意思是你可以通过socket.read
得到socket返回的值,但是你需要等待一段时间。原因是因为您试图用socket.read
读取整个流。这需要时间你可以通过执行以下操作来找出socket返回的内容:顺便说一句,Nagle's algorithm也让它变慢了。
close_write
所做的是让客户端半关闭套接字。当服务器端注意到这一点时,它也会关闭自己的端。这样你就可以很快读完阅读。或者你可以使用
IO::select
。正如文档所说:它监视给定的IO对象数组,等待一个或多个IO对象准备好阅读,准备好写入,并分别有挂起的异常,并返回一个包含这些IO对象数组的数组。如果给定了可选的超时值,并且在超时秒内没有IO对象就绪,则返回nil。
这里我们传递第一个参数,它是对象
ready for reading
,最后一个是你想要设置的超时。这意味着如果阅读在10秒内没有准备好,它将返回nil,然后引发超时错误。