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);
堆栈追踪:
我的代码
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
相关产品推荐
相关产品推荐

