分块传输编码终止符序列和 TCP recv()


import ssl
import socket
ssl_context = ssl.create_default_context()
target = 'swapi.co' 
port = 443 
resource = '/api/people/1/'
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
secure_client = ssl_context.wrap_socket(client, server_hostname=target)
send_str = 'GET {} HTTP/1.1rnHost: {}:{}rnrn'.format(resource, target, str(port))
secure_client.connect((target, port))
secure_client.send(send_str.encode()) 
print(send_str)
print(len(secure_client.recv(8192))) # 1282
print(len(secure_client.recv(8192))) # 5. Why?

上面是一个简单的Python程序,它使用TCP套接字向星球大战API发送HTTP请求。

这是发送的请求:

GET /api/people/1/ HTTP/1.1
Host: swapi.co:443

响应标头中包含Transfer-Encoding: chunked。当执行第一个 recv 时,将获得标头和第一个块。但是,要获取带有终止符序列 ("0\r\r")的最后一个块,必须调用第二个 recv。此行为的根本原因是什么?

TCP 是一种提供字节流的协议。它不提供任何将字节"粘合"到消息中的方法。当您呼叫recv时,您将收到的实际字节数是任意的,并且取决于各种不同的因素,例如另一端的确切实现,您呼叫recv的速度,网络的最大消息大小等。这没有任何意义。

由于您在查询中指示支持 HTTP 版本 1.1,因此允许服务器使用客户端需要支持的任何编码 HTTP 1.1。这包括这种形式的分块编码,它使用一个或多个数据"块",每个数据块前面都有一个大小指示器。这对于输出由脚本生成并且服务器在生成整个响应之前不知道它有多大的情况非常方便。此编码方案允许立即开始发送。

不要在 HTTP 查询中声明 HTTP 1.1 合规性,除非您的代码支持 HTTP 1.1 标准所说的客户端"必须"支持的所有内容。

这是因为在分块传输编码中,数据流被分成一系列不重叠的"块"。这些块彼此独立地发送和接收。

最新更新