You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内存BIO场景下如何实现SSL_pending功能?

问题分析与解决方案

你遇到的核心问题是:使用内存BIO(BIO_s_mem)搭配Winsock实现异步SSL通信时,往输入BIO写入套接字数据后,OpenSSL不会自动解析处理这些数据,导致SSL_pending()无法检测到待处理的应用数据——因为这些数据还停留在BIO层,没有被SSL层解密并放入内部应用缓冲区。

为什么SSL_pending()不工作?

SSL_pending()仅检测SSL层内部已解密的应用数据队列,不会主动扫描输入BIO中的原始SSL记录。只有当SSL层主动从输入BIO读取并处理数据后,解密后的应用数据才会被存入内部缓冲区,SSL_pending()才能返回正确值。

可行的解决方案

要实现无需读取数据就能知晓待处理数据的需求,核心是触发SSL层处理输入BIO中的数据,同时不消耗应用数据。最合理的方式是使用SSL_peek()配合极小缓冲区:

具体实现步骤

  1. 调用SSL_peek(),传入一个1字节的缓冲区(避免不必要的数据复制)。该函数会触发SSL层完成以下操作:
    • 从输入BIO读取SSL记录;
    • 完成握手、重协商、心跳等SSL层操作;
    • 将解密后的应用数据存入内部缓冲区,但不会取出数据。
  2. 处理SSL_peek()的返回值,尤其是SSL_ERROR_WANT_WRITE(需要发送SSL层生成的输出数据,比如握手响应)。

代码示例

// 往输入BIO写入套接字接收的数据后,触发SSL层处理
char dummy_buf[1];
int ret = SSL_peek(ssl, dummy_buf, sizeof(dummy_buf));

if (ret < 0) {
    int err_code = SSL_get_error(ssl, ret);
    if (err_code == SSL_ERROR_WANT_WRITE) {
        // 处理输出BIO中的待发送数据(如握手包、重协商数据)
        char send_buf[1024];
        int send_len;
        while ((send_len = BIO_read(ssl_output, send_buf, sizeof(send_buf))) > 0) {
            // 将数据发送到Winsock套接字
            send(your_socket, send_buf, send_len, 0);
        }
        // 发送完成后可再次尝试调用SSL_peek(),确保数据处理完成
        ret = SSL_peek(ssl, dummy_buf, sizeof(dummy_buf));
    } else if (err_code != SSL_ERROR_WANT_READ) {
        // 处理其他错误(如SSL协议错误、连接断开)
        // ...
    }
}

// 此时SSL_pending()会返回正确的待处理应用数据长度
int pending_data_len = SSL_pending(ssl);

注意事项

  • 每次往输入BIO写入新数据后,都需要执行一次上述触发操作,才能保证SSL_pending()的准确性。
  • SSL_peek()的返回值>0时,说明已有解密后的应用数据在内部缓冲区;返回0表示连接已关闭;返回<0且错误码为SSL_ERROR_WANT_READ时,说明输入BIO中的数据还不足以完成SSL层处理(需要等待更多数据)。

内容的提问来源于stack exchange,提问作者TrisT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 15:22:43