为了获得最佳性能,传递给接收方 SSL_read() 调用的适当缓冲区大小是多少?

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

我正在使用 Openssl 编写客户端服务器应用程序并使用 TLS 协议进行通信。

在我的服务器中,它向客户端发送可变长度的消息,范围从 100 字节到 30 KB 大小的消息。

在客户端程序中我使用非阻塞套接字来实现Openssl TLS接收。

我的问题是,为了获得最佳性能,我应该传递给 SSL_read() 调用的适当缓冲区大小是多少?

如果我将接收缓冲区设置为 100 字节,是否会导致套接字上的 SSL_read() 进行过多的 read() 系统调用,甚至构造记录,然后返回实际消息,以防服务器发送32KB 消息?

SSL-read() 执行 read() 系统调用时使用的缓冲区大小与我传递给 SSL_read() 调用的缓冲区大小不同。如果是这样,我在哪里可以找到有关 SSL_read() 如何优化流程的文档?

ssl openssl cryptography
1个回答
0
投票

如果您查看

SSL_read
SSL_pending
的文档,您会发现很多信息。其中:

SSL_read
读取功能基于 SSL/TLS 记录工作。数据是 以记录形式接收(最大记录大小为16kB)。仅当一个 记录已完全接收,是否可以处理(解密 和完整性检查)。因此,未检索到的数据 最后一次读取调用仍然可以在 SSL 层内缓冲,并且将 在下一次读取调用时检索。

这告诉您 OpenSSL 在后台做了很多事情,您在

SSL_read
获得的数据甚至可能不是它从套接字读取的数据。此外,即使 OpenSSL 确实从套接字获取了数据,您甚至可能根本无法从 OpenSSL 获取任何数据:

SSL_pending
因此,有可能不再有字节可从 底层 BIO(因为 OpenSSL 已经读取了它们)并且 SSL_pending() 返回 0,即使可读的应用程序数据字节 可用(因为数据位于未处理的缓冲记录中)。

SSL_read
如果底层 BIO 处于阻塞状态,则读取函数仅在读取操作完成或发生错误后才会返回,除非已处理非应用程序数据记录且未设置 SSL_MODE_AUTO_RETRY。
(...)
如果底层 BIO 是非阻塞的,当底层 BIO 无法满足函数继续操作的需求时,读取函数也会返回。

也许对于你的问题更重要的是:

SSL_read
如果 num (读取大小参数) 高于缓冲的字节数,则读取函数将返回缓冲的字节。如果缓冲区中没有更多字节,则读取函数将触发下一条记录的处理。只有当记录被完全接收并处理时,读取函数才会返回报告成功。 最多返回一条记录的内容。 由于 SSL/TLS 记录的大小可能会超过底层传输(例如 TCP)的最大数据包大小,因此 可能需要从传输层读取多个数据包在记录完成并且读取调用可以成功之前.

还有一些关于 SSL_pending 的有趣段落(关于

SSL_CTX_set_read_ahead
SSL_CTX_set_split_send_fragment
),但实际上我建议完整阅读 SSL_send 和 SSL_pending 页面。

希望我能明确指出,您无法真正控制 OpenSSL 选择从套接字读取的方式/时间。您调用 SSL_read 只会在必要时导致套接字读取。即使您的缓冲区非常小,OpenSSL 也会等待,直到您从其内部输出缓冲区中清除了足够的数据。然后它将处理任何排队的未处理数据并将其放入内部输出缓冲区中,以便您可以再次将其读出。只有当感觉没有更多数据备份时,对 SSL_read 的调用才会导致套接字读取。

本质上,从你的角度来看,这似乎并不是特别重要..无论缓冲区大小如何,它都是来自 OpenSSL 缓冲区的内存副本,而不是隐式的系统调用。
默认情况下,您将读取不超过一条记录 (≤16kB),因此,如果您使用大量数据,我可能会建议分配一次 16kB 缓冲区并重复使用它。
由于您没有处理大量数据,因此它可能无关紧要。

最后一点:即使使用普通套接字,较小的读取缓冲区大小也可能只是效率问题。您必须将它们做得非常小,以使这些内核调用花费很长时间,从而导致拥塞。数据传输也必须非常快,处理器(在大多数应用程序中)比网络链接快几个数量级。因此,在一般速度较慢的情况下,我倾向于“只使用带有使代码最具可读性和简单性的大小的recv”。

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