使用libssh2.1.10这段代码内存大量激增(已解决),不知道时什么问题,考虑使用libssh。
libssh使用难度比较高,可以直接使用openssl
#libssh 项目构建
cmake -G "Visual Studio 14 2015" -DBUILD_SHARED_LIBS=ON -DWITH_MBEDTLS=OFF -DWITH_GCRYPT=OFF -DCMAKE_INSTALL_PREFIX=E:\devlibs\libs/libssh -DCMAKE_GENERATOR_TOOLSET="v140_xp" -DOPENSSL_ROOT_DIR=E:\devlibs\libs\openssl -DOPENSSL_CRYPTO_LIBRARY=E:\devlibs\libs\openssl\lib -DZLIB_LIBRARY=E:\devlibs\libs\zlib\lib -DZLIB_INCLUDE_DIR=E:\devlibs\libs\zlib\include ..
//libssh2 内存泄漏代码,清楚的大神,请指教。
//20240314已经解决
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <iostream>
#include <cstring>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
class SFTPClient {
public:
SFTPClient(const std::string &hostname, int port, const std::string &username, const std::string &password)
: hostname(hostname), port(port), username(username), password(password), sock(INVALID_SOCKET), session(nullptr), sftp_session(nullptr) {
}
~SFTPClient() {
disconnect();
}
bool WaitConnect()
{
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
fd_set write, err;
FD_ZERO(&write);
FD_ZERO(&err);
FD_SET(sock, &write);
FD_SET(sock, &err);
// check if the socket is ready
int rc = select(sock + 1, NULL, &write, &err, &tv);
switch (rc)
{
case 0:
std::cout << ("connect server timeout");
case -1:
std::cout << ("connect server select (%d)", errno);
default:
break;
}
if (!FD_ISSET(sock, &write))
{
std::cout << ("select write socket failed: %d", errno);
}
int error = WSAEINPROGRESS;
int len = sizeof(int);
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)(&error), (socklen_t*)&len);
if (error)
{
std::cout << ("connect WSAEINPROGRESS getsockopt[SO_ERROR] : %d");
}
return true;
}
bool connect() {
// 创建socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
std::cerr << "Failed to create socket" << std::endl;
return false;
}
// 设置socket为非阻塞模式
u_long mode = 1; // 非阻塞模式
if (ioctlsocket(sock, FIONBIO, &mode) != NO_ERROR) {
std::cerr << "Failed to set socket non-blocking" << std::endl;
return false;
}
sockaddr_in sin{};
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_pton(AF_INET, hostname.c_str(), &sin.sin_addr);
// 非阻塞connect
if (::connect(sock, (sockaddr*)(&sin), sizeof(sin)) == SOCKET_ERROR) {
if (WSAGetLastError() != WSAEWOULDBLOCK) {
std::cerr << "Failed to connect" << std::endl;
return false;
}
WaitConnect();
}
// 创建一个SSH会话
session = libssh2_session_init();
if (!session) {
std::cerr << "Failed to create libssh2 session" << std::endl;
return false;
}
libssh2_session_set_blocking(session, 0); // 设置session为非阻塞模式
// 进行SSH会话的握手
int rc;
do {
rc = libssh2_session_handshake(session, sock);
} while (rc == LIBSSH2_ERROR_EAGAIN);
if (rc) {
std::cerr << "Failure establishing SSH session: " << rc << std::endl;
return false;
}
// 用户认证
do {
rc = libssh2_userauth_password(session, username.c_str(), password.c_str());
} while (rc == LIBSSH2_ERROR_EAGAIN);
if (rc) {
std::cerr << "Authentication by password failed." << std::endl;
return false;
}
// 初始化SFTP会话
do {
sftp_session = libssh2_sftp_init(session);
} while (!sftp_session && libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN);
if (!sftp_session) {
std::cerr << "Unable to init SFTP session" << std::endl;
return false;
}
return true;
}
void disconnect() {
if (sftp_session) {
libssh2_sftp_shutdown(sftp_session); //这里需要采用无阻塞模式释放。才能解决内存泄漏问题
sftp_session = nullptr;
}
if (session) {
libssh2_session_disconnect(session, "Normal Shutdown");
libssh2_session_free(session);
session = nullptr;
}
if (sock != INVALID_SOCKET) {
closesocket(sock);
sock = INVALID_SOCKET;
}
//libssh2_exit();
//WSACleanup();
}
private:
std::string hostname;
int port;
std::string username;
std::string password;
SOCKET sock;
LIBSSH2_SESSION *session;
LIBSSH2_SFTP *sftp_session;
};
#include <memory>
void test_once_memory()
{
std::unique_ptr<SFTPClient> client = std::make_unique<SFTPClient>("192.168.2.121", 22, "abc", "123456");
if (client->connect()) {
std::cout << "Connected successfully" << std::endl;
// 这里可以添加更多的SFTP操作,例如上传、下载文件等
}
else {
std::cerr << "Failed to connect" << std::endl;
}
}
int main() {
#ifdef WIN32
WSADATA wsadata;
int err;
err = WSAStartup(MAKEWORD(2, 0), &wsadata);
if (err != 0) {
fprintf(stderr, "WSAStartup failed with error: %d\n", err);
return 1;
}
#endif
// 初始化libssh2
if (libssh2_init(0) != 0) {
std::cerr << "libssh2 initialization failed" << std::endl;
return false;
}
test_once_memory();
WSACleanup();
return 0;
}