// sshmanager.cpp #include "sshmanager.h" SSHManager* SSHManager::m_instance = nullptr; SSHManager* SSHManager::instance() { if (!m_instance) { m_instance = new SSHManager(); } return m_instance; } SSHManager::SSHManager(QObject *parent) : QObject(parent) { m_session = nullptr; m_channel = nullptr; m_socket = nullptr; m_notifier = nullptr; m_sock = -1; // 初始化为无效值 } SSHManager::~SSHManager() { // 清理资源代码... // 关闭会话、释放socket等 } //连接 void SSHManager::connectAndStartShell(const QString &ip, const QString &port, const QString &username, const QString &password) { emit statusMessage(u8"开始连接服务器..."); Myip = ip; Myport = port; Myuser = username; Mypass = password; // 初始化 LibSSH2 if (libssh2_init(0) != 0) { connectionFailed(u8"初始化SSH失败!"); return; } // 创建 TCP 套接字 m_socket = new QTcpSocket(this); m_socket->setProxy(QNetworkProxy::NoProxy); // 创建一个定时器用于设置连接超时 QTimer *timer = new QTimer(this); timer->setSingleShot(true); // 只触发一次 QObject::connect(timer, &QTimer::timeout, [this]() { if (m_socket->state() != QAbstractSocket::ConnectedState) { m_socket->abort(); // 断开连接 connectionFailed(u8"连接超时!请检查网络或稍后重试。"); } }); // 连接信号 QObject::connect(m_socket, &QTcpSocket::connected, [this, timer]() { timer->stop(); // 连接成功,停止定时器 handleConnected(); }); QObject::connect(m_socket, QOverload::of(&QAbstractSocket::errorOccurred), [this, timer](QAbstractSocket::SocketError) { timer->stop(); // 连接出错,停止定时器 connectionFailed(u8"连接失败!检查IP和端口是否正确!"); }); // 开始非阻塞连接 m_socket->connectToHost(ip, port.toInt()); // 启动定时器,设置超时时间为 5 秒 timer->start(5000); } void SSHManager::handleConnected() { m_sock = m_socket->socketDescriptor(); // 创建会话并设置为非阻塞 m_session = libssh2_session_init(); libssh2_session_set_blocking(m_session, 0); // 开始会话建立 m_connectionStep = CONNECTION_STARTUP; trySessionStartup(); } void SSHManager::trySessionStartup() { int rc = libssh2_session_startup(m_session, m_sock); if (rc == LIBSSH2_ERROR_EAGAIN) { setupSocketNotifier(); return; } if (rc != 0) { connectionFailed(u8"启动会话失败!"); cleanup(); return; } // 会话建立成功,开始认证 m_connectionStep = AUTHENTICATION; tryAuthentication(); } void SSHManager::tryAuthentication() { int rc = libssh2_userauth_password(m_session, Myuser.toUtf8().constData(), Mypass.toUtf8().constData()); if (rc == LIBSSH2_ERROR_EAGAIN) { setupSocketNotifier(); return; } if (rc != 0) { connectionFailed(u8"账号或密码错误!请检查!"); cleanup(); return; } // 认证成功,创建通道 m_connectionStep = CHANNEL_CREATION; tryChannelCreation(); } void SSHManager::tryChannelCreation() { m_channel = libssh2_channel_open_session(m_session); if (!m_channel) { int rc = libssh2_session_last_error(m_session, nullptr, nullptr, 0); if (rc == LIBSSH2_ERROR_EAGAIN) { setupSocketNotifier(); return; } emit shellOutput(u8"\033[31mERROR: 无法创建终端通道\033[0m\r\n"); cleanup(); return; } // 通道创建成功,设置参数 libssh2_channel_handle_extended_data(m_channel, LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE); m_connectionStep = PTY_SETUP; tryPtySetup(); } void SSHManager::tryPtySetup() { int rc = libssh2_channel_request_pty(m_channel, "xterm-256color"); if (rc == LIBSSH2_ERROR_EAGAIN) { setupSocketNotifier(); return; } if (rc != 0) { emit shellOutput(u8"\033[31mERROR: 无法分配伪终端\033[0m\r\n"); cleanup(); return; } // PTY设置成功,启动shell m_connectionStep = SHELL_START; tryShellStart(); } void SSHManager::tryShellStart() { int rc = libssh2_channel_shell(m_channel); if (rc == LIBSSH2_ERROR_EAGAIN) { setupSocketNotifier(); return; } if (rc != 0) { emit shellOutput(u8"\033[31mERROR: 无法启动Shell\033[0m\r\n"); cleanup(); return; } // Shell启动成功,设置数据监听 m_notifier = new QSocketNotifier(m_sock, QSocketNotifier::Read, this); connect(m_notifier, &QSocketNotifier::activated, this, &SSHManager::readShellOutput); emit shellOutput(u8"\033[32m已连接到服务器,开始交互会话...\033[0m\r\n"); connectionSuccess(); } void SSHManager::setupSocketNotifier() { // 先销毁旧的通知器 if (m_notifier) { m_notifier->setEnabled(false); // 立即禁用 m_notifier->deleteLater(); // 安全删除 m_notifier = nullptr; // 重置指针 } int directions = libssh2_session_block_directions(m_session); // 优先处理写操作 QSocketNotifier::Type type = QSocketNotifier::Read; if (directions & LIBSSH2_SESSION_BLOCK_OUTBOUND || !m_writeBuffer.isEmpty()) { type = QSocketNotifier::Write; } else if (directions & LIBSSH2_SESSION_BLOCK_INBOUND) { type = QSocketNotifier::Read; } m_notifier = new QSocketNotifier(m_sock, type, this); connect(m_notifier, &QSocketNotifier::activated, this, [this]() { // 处理读写事件 if (m_notifier->type() == QSocketNotifier::Write) { trySendData(); } handleNextStep(); }); } void SSHManager::handleNextStep() { switch (m_connectionStep) { case CONNECTION_STARTUP: trySessionStartup(); break; case AUTHENTICATION: tryAuthentication(); break; case CHANNEL_CREATION: tryChannelCreation(); break; case PTY_SETUP: tryPtySetup(); break; case SHELL_START: tryShellStart(); break; default: break; } } void SSHManager::readShellOutput() { char buffer[4096]; while (true) { int nbytes = libssh2_channel_read_ex(m_channel, LIBSSH2_CHANNEL_EXTENDED_DATA_DEFAULT, buffer, sizeof(buffer)); if (nbytes > 0) { emit shellOutput(QByteArray(buffer, nbytes)); } else if (nbytes == LIBSSH2_ERROR_EAGAIN) { break; } else { if (nbytes != LIBSSH2_ERROR_CHANNEL_CLOSED) { emit shellOutput(u8"\033[31m连接异常断开\033[0m\r\n"); } cleanup(); break; } } } void SSHManager::cleanup() { if (m_channel) { libssh2_channel_free(m_channel); m_channel = nullptr; } if (m_session) { libssh2_session_free(m_session); m_session = nullptr; } if (m_socket) { m_socket->disconnectFromHost(); m_socket->deleteLater(); m_socket = nullptr; } libssh2_exit(); } // 在实现文件 SSHManager.cpp 中添加以下实现 void SSHManager::sendInput(const QString &input) { if (!m_channel || !m_session) { emit shellOutput(u8"\033[31m错误:连接未建立\033[0m\r\n"); return; } // 将输入转换为UTF-8并追加换行符 QByteArray data = input.toUtf8() + '\n'; // 添加到发送缓冲区 m_writeBuffer.append(data); // 立即尝试发送 trySendData(); } void SSHManager::trySendData() { while (!m_writeBuffer.isEmpty()) { // 非阻塞模式发送 ssize_t n = libssh2_channel_write_ex( m_channel, LIBSSH2_CHANNEL_EXTENDED_DATA_DEFAULT, m_writeBuffer.constData() + m_writeOffset, m_writeBuffer.size() - m_writeOffset ); if (n > 0) { // 更新发送偏移 m_writeOffset += n; // 如果全部发送完成 if (m_writeOffset >= m_writeBuffer.size()) { m_writeBuffer.clear(); m_writeOffset = 0; return; } } else if (n == LIBSSH2_ERROR_EAGAIN) { // 设置写监控 setupSocketNotifier(); return; } else { // 处理发送错误 emit shellOutput(u8"\033[31m发送失败,连接可能已断开\033[0m\r\n"); cleanup(); return; } } } //判断是否连接 bool SSHManager::isConnected() { if (!m_session) { connectionFailed(u8"SSH连接已被断开,可能是服务器设置了响应时间"); return false; } int rc = libssh2_session_last_error(m_session, nullptr, nullptr, 0); return rc == 0; } //重连 void SSHManager::reconnect() { // 先清理现有连接资源 if (m_session) { libssh2_session_disconnect(m_session, "Reconnecting"); libssh2_session_free(m_session); m_session = nullptr; } if (m_socket) { m_socket->close(); m_socket->deleteLater(); m_socket = nullptr; } libssh2_exit(); // 重新连接 connectAndStartShell(Myip,Myport,Myuser,Mypass); statusMessage(u8"重新连接服务器成功"); } void SSHManager::disconnectFromServer() { // 清理交互式通道 if (m_channel) { libssh2_channel_close(m_channel); libssh2_channel_free(m_channel); m_channel = nullptr; } // 清理终端监听器 if (m_notifier) { m_notifier->setEnabled(false); delete m_notifier; m_notifier = nullptr; } // 清理SSH会话 if (m_session) { libssh2_session_disconnect(m_session, "User initiated disconnect"); libssh2_session_free(m_session); m_session = nullptr; } // 清理套接字 if (m_socket) { if (m_socket->state() == QAbstractSocket::ConnectedState) { m_socket->disconnectFromHost(); if (!m_socket->waitForDisconnected(1000)) { m_socket->abort(); } } m_socket->deleteLater(); m_socket = nullptr; } // 通知界面连接已断开 emit disconnected(); emit statusMessage(u8"已断开与服务器的连接"); }