1

我正在尝试向网站发送 HTTP 请求并读取它返回的数据。我尝试的第一个网站运行成功。它返回了大约 4 个数据包,然后返回了一个脚本捕获并终止的 0 个数据包。

但是,尝试加载http://www.google.com/并不能以这种方式工作。相反,它返回大约 10 个相同长度的数据包,最后一个较小的数据包,然后继续超时。发生这种情况正常吗?这一切都取决于主机使用的服务器吗?

如果有人可以推荐一种使用 socket.recv() 读取的替代方法,该方法会考虑到并不总是发送最终的空数据包,我们将不胜感激。谢谢。

    try:
        data = s.recv(4096)

        while True:
            more = s.recv(4096)
            print len(more)
            if not more:
                break
            else:
                data += more
    except socket.timeout:
        errMsg = "Connection timed-out while connecting to %s. Request headers were as     follows: %s", (parsedUrl.netloc, rHeader.headerContent)
        self.logger.exception(errMsg)
        raise Exception
4

3 回答 3

3

TCP 不会给你“数据包”,而是从另一端发送的连续字节。它是一个流recv()为您提供当前可用的流的块。您将它们缝合在一起并解析流内容。

HTTP是一种相当复杂的协议,需要手动制定,因此您可能希望从一些现有的库(如httplib )开始。

于 2012-08-24T14:12:06.997 回答
3

对于 HTTP,使用请求而不是自己编写。

> ipython

In [1]: import requests

In [2]: r = requests.get('http://www.google.com')

In [3]: r.status_code
Out[3]: 200

In [4]: r.text[:80]
Out[4]: u'<!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage">'

In [5]: len(r.text)
Out[5]: 10969
于 2012-08-24T14:29:54.100 回答
2

可能是 Google 使用Keep-Alive来保持套接字打开,以便为进一步的请求提供服务。这将需要解析标头并读取确切的字节数。

根据您使用的 HTTP 版本,您必须添加Connection: Keep-Alive或不添加标头。(这可能是最简单的解决方案:只需使用 HTTP/1.0 而不是 1.1。)

如果您仍然使用该功能,您将不得不接收您的第一块数据,并且

  1. 解析是否有'\r\nContent-Length: '内部,如果有,则获取该内部和下一个之间的字节'\r\n'并将它们转换为数字。那是你的尺寸。
  2. 看看你'\r\n\r\n'的数据中是否有一个。如果是这样,那就是标题的结尾。从这里,您必须读取上面提到的确切字节数。

例子:

import socket
s = socket.create_connection(('www.google.com', 80))
s.send("GET / HTTP/1.1\r\n\r\n")
x = s.recv(10000)
poscl = x.lower().find('\r\ncontent-length: ')
poseoh = x.find('\r\n\r\n')
if poscl < poseoh and poscl >= 0 and poseoh >= 0:
    # found CL header
    poseocl = x.find('\r\n',poscl+17)
    cl = int(x[poscl+17:poseocl])
    realdata = x[poseoh+4:]

现在,您在 中获得了内容长度cl和有效载荷数据的(开始)realdata。此请求丢失的字节数为missing = cl - len(realdata)。如果是0,你就拥有了一切;如果不是,则执行s.read(missing)并重新计算missing,直到为 0。

上面的代码是要完成的工作的简单开始;有些地方您可能需要recv()进一步了解才能继续。

这是相当复杂的。到目前为止,更简单的方法是

  1. Connection: close在请求中使用 HTTP 1.1 的标头,
  2. 使用 HTTP 1.0,
  3. 使用为此任务设计的库之一,而不是重新发明轮子。
于 2012-08-24T14:28:09.160 回答