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

基于F-Stack+DPDK的C++ EPOLL客户端SSL_connect阻塞求助

问题分析与解决方案

核心原因

F-Stack 是用户态网络栈,其 socket 并非系统标准套接字,直接使用 OpenSSL 原生的阻塞 SSL_connect 会导致 IO 逻辑不兼容,触发循环等待(对应你看到的 4097 回调标识),最终阻塞程序。同时未适配 F-Stack 的 IO 接口与 OpenSSL 绑定,会引发数据传输异常(乱码)。

具体解决步骤

1. 将 SSL 对象强制设为非阻塞模式

F-Stack 不支持系统级的 fcntl 非阻塞设置,需直接对 SSL 对象配置:

// OpenSSL 3.x 直接调用该接口设置非阻塞
SSL_set_nonblocking(ssl, 1);
// 额外开启自动重试与分段写入模式,适配用户态网络栈
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE);

2. 用事件驱动替换阻塞的 SSL_connect

结合 F-Stack 的 EPOLL 机制,循环处理握手流程,不再依赖阻塞调用:

int ret;
while (true) {
    ret = SSL_connect(ssl);
    if (ret == 1) {
        // TLS 握手成功,跳出循环
        break;
    }

    int ssl_err = SSL_get_error(ssl, ret);
    if (ssl_err == SSL_ERROR_WANT_READ) {
        // 注册 EPOLLIN 事件,等待可读后继续握手
        struct epoll_event event = {.events = EPOLLIN, .data.fd = ff_fd};
        epoll_ctl(epfd, EPOLL_CTL_MOD, ff_fd, &event);
    } else if (ssl_err == SSL_ERROR_WANT_WRITE) {
        // 注册 EPOLLOUT 事件,等待可写后继续握手
        struct epoll_event event = {.events = EPOLLOUT, .data.fd = ff_fd};
        epoll_ctl(epfd, EPOLL_CTL_MOD, ff_fd, &event);
    } else {
        // 握手失败,处理错误
        fprintf(stderr, "TLS 握手失败,错误码:%d\n", ssl_err);
        goto cleanup;
    }

    // 等待 EPOLL 事件触发
    int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
    if (nfds < 0) {
        perror("epoll_wait 失败");
        goto cleanup;
    }
}

3. 绑定 F-Stack 专属 IO 接口到 OpenSSL

OpenSSL 默认使用系统 read/write,必须替换为 F-Stack 的 ff_read/ff_write,通过自定义 BIO 实现:

// 自定义 F-Stack 读写回调
static int ff_ssl_read(BIO *bio, char *buf, int num) {
    int fd = BIO_get_fd(bio, NULL);
    return ff_read(fd, buf, num);
}

static int ff_ssl_write(BIO *bio, const char *buf, int num) {
    int fd = BIO_get_fd(bio, NULL);
    return ff_write(fd, buf, num);
}

// 创建并绑定自定义 BIO
BIO_METHOD *ff_bio_method = BIO_meth_new(BIO_TYPE_SOCKET, "F-Stack Socket BIO");
BIO_meth_set_read(ff_bio_method, ff_ssl_read);
BIO_meth_set_write(ff_bio_method, ff_ssl_write);
BIO_meth_set_destroy(ff_bio_method, BIO_destroy_socket);

BIO *bio = BIO_new(ff_bio_method);
BIO_set_fd(bio, ff_fd, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);

4. 排查版本兼容性问题

你手动升级了 OpenSSL 3.1.3,需确保编译与运行时的库路径一致:

  • 编译时指定 OpenSSL 3.1.3 的链接参数:-L/path/to/openssl-3.1.3/lib -lssl -lcrypto
  • 运行前设置环境变量:export LD_LIBRARY_PATH=/path/to/openssl-3.1.3/lib:$LD_LIBRARY_PATH
  • 确认 F-Stack 编译时也链接了同一版本的 OpenSSL

5. 解决乱码问题

乱码是因为握手阶段的二进制 TLS 数据被误当明文打印,或缓冲区配置异常:

  • 不要在 TLS 握手完成前打印 socket 接收的数据
  • 通过 ff_setsockopt 配置合适的收发缓冲区大小:
int buf_size = 16384;
ff_setsockopt(ff_fd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size));
ff_setsockopt(ff_fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 09:36:11