使用python套接字接收大的http请求

问题描述 投票:1回答:2

我正在使用python套接字来接收Web样式和soap请求。我的代码是

import socket
svrsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname();
svrsocket.bind((host,8091))
svrsocket.listen(1)
clientSocket, clientAddress = svrsocket.accept()
message = clientSocket.recv(4096)

但是,我收到的一些肥皂要求非常庞大。 650k巨大,这可能会变成数Mb。而不是我尝试的单个recv

message = ''
while True:
  data = clientSocket.recv(4096)
  if len(data) == 0:
   break;
  message = message + data

但是尽管python socket how to说我应该,但是我从来没有用firefox或safari收到0字节数据块。

如何解决这个问题?

python http sockets soap
2个回答
1
投票

[遗憾的是,您无法在TCP级别上解决此问题-HTTP定义了自己的连接管理,请参见RFC 2616。这基本上意味着您需要解析流(至少是标头)以弄清何时可以关闭连接。

在此处查看相关问题-https://stackoverflow.com/search?q=http+connection


1
投票

Hiya

首先,我想加强前面的回答说的话

很遗憾,您无法在TCP级别解决此问题

这是真的,你不能。但是,您可以在tcp套接字的顶部实现http解析器。这就是我想在这里探索的。让我们开始吧

问题和期望的结果

目前,我们正在努力寻找数据流的终点。我们希望流以固定的结尾结束,但是现在我们知道HTTP没有定义任何消息后缀

但是,我们继续前进。

我们现在可以问一个问题,“我们能事先知道消息的长度吗?”答案是肯定的!有时...

您看到HTTP/1.1定义了一个名为Content-Length的标头,正如您期望的那样,它具有我们想要的内容长度;但是阴影中还有其他东西:Transfer-Encoding: chunked。除非您真的想了解它,否则我们暂时不使用它。

解决方案

这里是一个解决方案。您一开始不会知道其中的一些功能,但是如果您坚持我的看法,我将进行解释。好吧...深吸一口气。

假设conn是到所需HTTP服务器的套接字连接

...

    rawheaders = recvheaders(conn,end=CRLF)
    headers = dict_headers(io.StringIO(rawheaders))
    l_content = headers['Content-Length']

    #okay. we've got content length by magic

    buffersize = 4096
    while True:
        if l_content <= 0: break

        data = clientSocket.recv(buffersize)
        message += data

        l_content -= len(data)

...

如您所见,我们已经知道Content-Lengthl_content进入了循环>

[我们迭代时,通过从clientSocket.recv(buff)中减去l_content的长度来跟踪剩余的内容。

[当我们读取的数据至少等于l_content时,我们就完成了

if l_content <= 0: break

沮丧

[注意:对于接下来的一些内容,我将提供伪代码,因为该代码可能有点密集]

所以现在您问的是rawheaders = recvheaders(conn)是什么,headers = dict_headers(io.StringIO(rawheaders))是什么,而我们如何获得headers['Content-Length']?!

对于入门者,recvheadersHTTP/1.1规范未定义消息后缀,但确实定义了一些有用的信息:http headers的后缀!后缀为CRLF\r\n。这意味着我们在读取CRLF时便知道何时收到标头。所以我们可以写一个类似

的函数
def recvheaders(sock):
    rawheaders = ''
    until we read crlf:
        rawheaders = sock.recv()
    return rawheaders

接下来,解析标题。

def dict_header(ioheaders:io.StringIO):
    """
    parses an http response into the status-line and headers
    """
    #here I expect ioheaders to be io.StringIO
    #the status line is always the first line
    status = ioheaders.readline().strip()
    headers = {}
    for line in ioheaders:
        item = line.strip()
        if not item:
            break
        //headers look like this 
        //'Header-Name' : 'Value'
        item = item.split(':', 1)
        if len(item) == 2:
            key, value = item
            headers[key] = value
    return status, headers

这里我们读到status line,然后我们继续遍历其余每行并使用[]从[key,value]建立Header: Value

    item = line.strip()
    item = item.split(':', 1)
    # We do split(':',1) to avoid cases like
    # 'Header' : 'foo:bar' -> ['Header','foo','bar']
    # when we want ---------> ['Header','foo:bar']

然后我们获取该列表并将其添加到headers字典

    #unpacking
    #key = item[0], value = item[1]
    key, value = item
    header[key] = value

BAM,我们已经创建了标题映射

headers['Content-Length']从那里掉出来。

所以,

只要您可以保证始终收到Content-Length,此结构就会起作用如果您已经做到了这一点,感谢您抽出宝贵的时间,希望对您有所帮助!

TLDR;如果您想知道带有套接字的HTTP消息的长度,请编写一个HTTP解析器

© www.soinside.com 2019 - 2024. All rights reserved.