python-3.x - Python SSL - 当数据大于 1400 时 recv 被偏移

标签 python-3.x ssl buffer

我在 Python 中使用 ssl 模块,遇到了一个似乎是缓冲区的小问题。

我有以下过程来处理来自套接字的数据,我还添加了一个 while 循环,使用基于 this 的 pending问题,但并没有解决问题。我也加大了缓冲区的大小,但无济于事。

RECV_BUFFER = 131072
def handle(client_socket):
    try:
        rxdata = client_socket.recv(RECV_BUFFER)
        if rxdata:
                print("Rx: " + rxdata.decode())
                while(client_socket.pending()):
                    rxdata = client_socket.recv(RECV_BUFFER)
                    sys.stdout.write(rxdata.decode())
    except Exception as e:
        print("Exception: " + str(e))

出于测试目的,我设置了一个用户输入,以便我可以直接进行测试。 GET/ 返回“Hello World”,而 GET/other 返回一个长字符串。每次缓冲区溢出时,返回值都会偏移 1,如下所示。

Command>GET /
Tx: GET /
Rx: HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Cloud-Trace-Context: a65f614b75674fa723b7d69c1af03a0e;o=1
Date: Sun, 02 Sep 2018 16:00:19 GMT
Server: My Frontend
Content-Length: 12

Hello World!
Command>GET /other
Tx: GET /other
Rx: HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Cloud-Trace-Context: 90033f7e308e07508106359c3e7c76d1
Date: Sun, 02 Sep 2018 16:00:23 GMT
Server: My Frontend
Content-Length: 1924

This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. T
Command>GET /
Tx: GET /
Rx: his is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. This is something else. End.
Command>GET /other
Tx: GET /other
Rx: HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Cloud-Trace-Context: 160b0cd5f80982bf1e7ab7dd5d94996d
Date: Sun, 02 Sep 2018 16:00:26 GMT
Server: My Frontend
Content-Length: 12

Hello World!

这是怎么回事,应该如何解决?

最佳答案

我不完全确定您要做什么,但我认为您的服务器基本上是这样工作的:

  1. 阅读命令(一行)。
  2. 立即发送完整的回复。

鉴于您使用的是 pending,它只检查 SSL 套接字中是否仍有解密数据,我的猜测是您假设数据是否由服务器在单个 中发送sent 那么它也会被客户端立即读取。但这种情况并非如此。这里实际发生的事情是这样的:

  1. 服务器发送很多天,比如 20000 字节。
  2. 在 SSL 级别,这些至少是两个 SSL 记录,因为单个记录的大小只能为 16384。因此,假设它将执行 16384 的记录和其余的记录(3616 字节)。<
  3. ssl_socket.revc(RECV_BUFFER) 至少会从底层 TCP 连接中读取与需要完整 SSL 记录一样多的数据。然后它将解密 SSL 记录并返回最多 RECV_BUFFER 字节的解密数据。
  4. ssl_socket.pending() 会告诉您 SSL 套接字中是否还有未读的解密数据。它不会检查底层 TCP 套接字是否有可用数据。如果 SSL 套接字中仍有数据,下一个 ssl_socket.recv(...) 将从这些数据返回,但不会尝试从底层 TCP 套接字读取更多数据。仅当 SSL 套接字中没有更多解密但未读数据可用时,recv 才会从底层 TCP 套接字读取更多信息 - 但在这种情况下,pending 将返回 false,因此您将永远不会尝试读取更多数据。

这意味着在您的 recv 中可能只读取和解密并返回第一条 SSL 记录。因此,如果您发送下一个命令,您将不会收到新的响应,但您实际上会从上一个请求中读取剩余的响应数据。

为了修正代码,您需要修正您的假设:SSL 需要被视为数据流而不是消息协议(protocol)(TCP 也是如此)。这意味着您不能假设消息已被完整读取并且将被完整返回,或者它在 SSL 对象中至少已经完整。相反,您要么需要预先知道响应的大小(例如在响应前加上长度前缀),要么需要有一些明确的标记表明响应已结束并一直读取到该标记。

关于python-3.x - Python SSL - 当数据大于 1400 时 recv 被偏移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52139071/

相关文章:

ssl - 使用 des3 生成私钥卡住了

javascript - 缓存音频缓冲区以防止每次解码音频数据

python - Boto3上传ServerSideEncryption

python - xlsxwriter 条件格式 icon_set 中间值 = 0 未显示正确的箭头

python - 拆分和排序数据框中的值

python-3.x - 如何使用 cx_freeze 在 python 中创建 .EXE 文件

java - 从智能卡写入和读取证书

c++ - Microsoft C++ HTTP 服务器 API (httpapi.lib) HttpReceiveClientCertificate 函数返回 ERROR_NOT_FOUND ( 1168 )

javascript - 缓冲客户端文件下载

ios - MTLBuffer 内容导致 EXC_BAD_ACCESS