【发布时间】:2016-11-07 00:11:02
【问题描述】:
我编写了一个将 OpenSSL 用于 SSL/TLS 的网络服务器。服务器发送和接收大块数据,并在两者之间执行各种转换。出于性能原因,转换主要使用向量信息(参见 POSIX 的 iovec)来完成,以避免昂贵的内存移动(memcpy() 等)。当数据准备好发送时,我使用 writev() POSIX 函数,该函数使用这些向量从内存中收集数据,并通常将其作为一个网络数据包发送。
现在使用 OpenSSL,这并不完全可能,因为据我所知,OpenSSL 仅提供 SSL_write() 函数。这意味着我必须为要发送的每个向量条目调用此函数。不幸的是,这会导致每个矢量数据块都在其自己的 SSL 帧中传输,从而引入了不必要的和不必要的网络开销。
我的问题是:SSL_writev() 是否等同于 writev()?或者一般来说,有没有一种技术可以告诉 OpenSSL 将 SSL_write() 数据存储到一个 SSL 应用程序记录(类型 22)中而不发送它(当然还有某种 flush() 函数)?
编辑:如下所述,一种可行的方法是在最终的单个 SSL_write() 调用之前将矢量数据整合到一个大块中。然而,有 2 个副本的连接开销(第一个在合并期间,第二个在 SSL_write() 执行 AES 加密时)。 理论上的 SSL_writev() 调用不会引入这种开销。
【问题讨论】:
-
我认为你需要一个“上拉”功能。即,将多个缓冲区合并为一个。
-
这正是我今天所做的。但它是相当昂贵的 b/c 它在内存中移动大量数据。
-
@ateska 但是它在内存中移动大量数据是相当昂贵的 b/c。 在 Linux 上,
writev()是 actually implemented 作为一个包装器在分配临时缓冲区的write()周围,将writev()缓冲区复制到临时缓冲区中,然后调用write()。如果您在 Linux 上运行并且writev()在没有 SSL 的情况下为您工作,只需编写您自己的SSL_writev()包装器。 -
@AndrewHenle - writev() 实现的好处。我希望它使用分散/收集内核功能。
-
@jww - 同意,高效的复制很重要。然而,这仍然意味着 SSL 版本将执行 2 个副本:第一个是“上拉”,第二个是 SSL 写入期间的 AES(或类似)加密。 SSE4/AVX 和 AES-NI 确实可以分别“加速”两者。我正在寻找将其合并为 1 个副本,这是 SSL_writev() 背后的原始想法。