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

Windows下用libssh2上传SFTP文件遇session启动阻塞问题求助

libssh2_session_startup调用时程序锁死问题

我尝试将本地文件上传至SFTP服务器,此前使用过socket但不熟悉libssh2。调用libssh2_session_startup时程序锁死,卡在session.c中_libssh2_wait_socket函数的以下select语句处:

rc = select(session->socket_fd + 1, readfd, writefd, NULL, has_timeout ? &tv : NULL);

堆栈追踪:
stacktrace

我的代码

bool UploadFileToSFTP(const std::wstring& sftpServer, int port, const std::wstring& username, const std::wstring& password, const std::wstring& localFilePath, const std::wstring& remoteFilePath) {

    // 解析IP
    addrinfo hints = {0};
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    addrinfo* pResult = NULL;
    int ret = getaddrinfo(toUtf8(sftpServer).c_str(), std::to_string(port).c_str(), &hints, &pResult);
    if(ret != 0) {
        std::cerr << "getaddrinfo错误: " << ret << std::endl;
        WSACleanup();
        return -1;
    }

    // 记录IP类型
    bool has_IPv4 = false;
    bool has_IPv6 = false;

    for(addrinfo* addr = pResult; addr != NULL; addr = addr->ai_next) {
        switch(addr->ai_family) {
        case AF_INET: { // IPv4
            has_IPv4 = true;
            std::cout << "IPv4 : " << addr_to_str(addr);
            break;
        }

        case AF_INET6: { // IPv6
            has_IPv6 = true;
            std::cout << "IPv6 : " << addr_to_str(addr);
            break;
        }
        }
    }

    // 连接服务器
    SOCKET sock = INVALID_SOCKET;

    if(has_IPv6) {
        // 优先尝试IPv6
        for(addrinfo* addr = pResult; addr != NULL; addr = addr->ai_next) {
            if(addr->ai_family != AF_INET6)
            { continue; }

            std::cout << "连接IPv6 : " << addr_to_str(addr) << " | 端口 : " << port << std::endl;

            sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
            if(sock == INVALID_SOCKET) {
                ret = WSAGetLastError();
                std::cerr << "socket错误: " << ret << std::endl;
                continue;
            }

            if(connect(sock, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR) {
                ret = WSAGetLastError();
                std::cerr << "connect错误: " << ret << std::endl;
                closesocket(sock);
                sock = INVALID_SOCKET;
                continue;
            }

            break;
        }
    }

    if((sock == INVALID_SOCKET) && (has_IPv4)) {
        // 尝试IPv4
        for(addrinfo* addr = pResult; addr != NULL; addr = addr->ai_next) {
            if(addr->ai_family != AF_INET)
            { continue; }

            std::cout << "连接IPv4 : " << addr_to_str(addr) << " | 端口 : " << port << std::endl;

            sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
            if(sock == INVALID_SOCKET) {
                ret = WSAGetLastError();
                std::cerr << "socket错误: " << ret << std::endl;
                continue;
            }

            if(connect(sock, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR) {
                ret = WSAGetLastError();
                std::cerr << "connect错误: " << ret << std::endl;
                closesocket(sock);
                sock = INVALID_SOCKET;
                continue;
            }

            break;
        }
    }

    freeaddrinfo(pResult);



    // 初始化libssh2
    int rc = libssh2_init(0);
    if(rc != 0) {
        std::cout << "初始化libssh2失败。" << std::endl;
        return false;
    }

    // 创建SSH会话
    LIBSSH2_SESSION* session = libssh2_session_init();
    if(!session) {
        std::cout << "创建SSH会话失败。" << std::endl;
        libssh2_exit();
        return false;
    }

    // 设置会话为阻塞模式
    libssh2_session_set_blocking(session, 1);

    libssh2_session_set_timeout(session, 10000);

    // 连接SFTP服务器
    rc = libssh2_session_startup(session, sock); // 此处锁死
    if(rc < 0) {
        char* last_error_msg=new char[256];
        int errlen = sizeof(last_error_msg);
        libssh2_session_last_error(session, &last_error_msg, &errlen, 1);

        std::cout << "建立SSH会话失败。" << std::endl;
        libssh2_session_disconnect(session, "建立SSH会话失败。");
        libssh2_session_free(session);
        libssh2_exit();
        return false;
    }


    // 密码认证
    rc = libssh2_userauth_password(session, toUtf8(username).c_str(), toUtf8(password).c_str());
    if(rc != 0) {
        std::cout << "密码认证失败。" << std::endl;
        libssh2_session_disconnect(session, "密码认证失败。");
        libssh2_session_free(session);
        libssh2_exit();
        return false;
    }

    // 打开本地文件
    FILE* localFile = _wfopen(localFilePath.c_str(), L"rb");
    if(!localFile) {
        std::cout << "打开本地文件失败。" << std::endl;
        libssh2_session_disconnect(session, "打开本地文件失败。");
        libssh2_session_free(session);
        libssh2_exit();
        return false;
    }

    // 获取文件大小
    fseek(localFile, 0, SEEK_END);
    int64_t fileSize = ftell(localFile);
    fseek(localFile, 0, SEEK_SET);

    // 初始化SFTP会话
    LIBSSH2_SFTP* sftpSession = libssh2_sftp_init(session);
    if(!sftpSession) {
        std::cout << "初始化SFTP会话失败。" << std::endl;
        fclose(localFile);
        libssh2_session_disconnect(session, "初始化SFTP会话失败。");
        libssh2_session_free(session);
        libssh2_exit();
        return false;
    }

    // 打开远程文件
    LIBSSH2_SFTP_HANDLE* sftpFile = libssh2_sftp_open(sftpSession, toUtf8(remoteFilePath).c_str(), LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH);
    if(!sftpFile) {
        std::cout << "打开远程文件失败。" << std::endl;
        fclose(localFile);
        libssh2_sftp_shutdown(sftpSession);
        libssh2_session_disconnect(session, "打开远程文件失败。");
        libssh2_session_free(session);
        libssh2_exit();
        return false;
    }// 分块上传文件
    std::vector<char> buffer(32768); // 32KB缓冲区
    size_t bytesRead = 0;
    int64_t totalBytesUploaded = 0;
    while((bytesRead = fread(buffer.data(), 1, buffer.size(), localFile)) > 0) {
        ssize_t bytesWritten = libssh2_sftp_write(sftpFile, buffer.data(), bytesRead);
        if(bytesWritten < 0) {
            std::cout << "写入远程文件失败。" << std::endl;
            fclose(localFile);
            libssh2_sftp_close(sftpFile);
            libssh2_sftp_shutdown(sftpSession);
            libssh2_session_disconnect(session, "写入远程文件失败。");
            libssh2_session_free(session);
            libssh2_exit();
            return false;
        }
        totalBytesUploaded += bytesWritten;
    }

    // 关闭本地和远程文件
    fclose(localFile);
    libssh2_sftp_close(sftpFile);
    libssh2_sftp_shutdown(sftpSession);

    // 断开并释放会话
    libssh2_session_disconnect(session, "上传完成。");
    libssh2_session_free(session);

    // 清理libssh2
    libssh2_exit();


    std::cout << "文件上传成功。总上传字节数: " << totalBytesUploaded << std::endl;

    return true;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:02:00