libssh2 基于poll() 和 libssh2_channel_exec()执行指令 实现监听服务器文件

256 阅读4分钟

实战踩坑 代码总结 libssh2_channel_poll()libssh2_channel_exec()libssh2 库中用于处理 SSH 通道的两个重要函数。下面是对这两个函数的功能和用法的详细讲解。

1. libssh2_channel_exec()

功能

  • libssh2_channel_exec() 函数用于在 SSH 通道上执行命令。它使得你可以通过 SSH 连接远程服务器并执行命令。

用法

  • 在调用此函数之前,你需要创建一个通道,并且使用 libssh2_channel_open_session() 打开会话。
  • 调用 libssh2_channel_exec() 传入要执行的命令。

示例代码

LIBSSH2_CHANNEL *channel;
channel = libssh2_channel_open_session(session);
if (channel == NULL) {
    // 错误处理
}

if (libssh2_channel_exec(channel, "ls -l") != 0) {
    // 错误处理
}

2. libssh2_channel_poll()

功能

  • libssh2_channel_poll() 函数用于检查通道的状态,判断它是否可以进行读写操作。此函数在处理非阻塞 I/O 时非常有用,特别是在需要同时管理多个通道时。

用法

  • 在调用此函数之前,需要确保已经创建了通道。然后,使用此函数来检查通道是否已经准备好读取或写入数据。

示例代码

struct pollfd fds[1];
fds[0].fd = libssh2_channel_get_fd(channel); // 获取通道的文件描述符
fds[0].events = POLLIN | POLLOUT;

while (1) {
    int rv = poll(fds, 1, -1); // 等待事件
    if (rv < 0) {
        perror("poll");
        break;
    }

    if (fds[0].revents & POLLIN) {
        char buffer[1024];
        int n = libssh2_channel_read(channel, buffer, sizeof(buffer));
        if (n > 0) {
            write(STDOUT_FILENO, buffer, n); // 输出到标准输出
        } else if (n < 0) {
            // 错误处理
            break;
        }
    }
}

总结

  • libssh2_channel_exec() 用于在 SSH 通道上执行命令,适合需要远程执行命令的场景。
  • libssh2_channel_poll() 用于监控通道的状态,适合需要处理非阻塞 I/O 和多个通道的复杂场景。

结合这两个函数,你可以高效地与远程系统进行交互,执行命令并处理输出

我最终实现多通道监听文件的代码如下:

#include "mainwindow.h"
#include<iostream>
#include <QApplication>
#include "libssh2.h"
#include<winsock2.h>
#include<QThread>
#include<QDebug>
using namespace std;

string username="*****";
string password="*****";
string ip="******";

SOCKET  Sock=INVALID_SOCKET;
LIBSSH2_SESSION *Session=nullptr; //һ���Ự
LIBSSH2_CHANNEL *ExecChannel;
LIBSSH2_CHANNEL *ListeningChannel[3]={nullptr,nullptr,nullptr}; //3������ͨ��
bool running;

bool connectToServer()
{
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        cout << "WSAStartup failed" << endl;
        return false;
    }

    Sock = socket(AF_INET, SOCK_STREAM, 0);
    if (Sock == INVALID_SOCKET) {
        cout << "Failed to create socket" << endl;
        WSACleanup();
        return false;
    }
    //���÷�������ַ
    sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(22);
    server_addr.sin_addr.s_addr = inet_addr(ip.c_str()); //

    //  connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0
    if (::connect(Sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0) {
        cout << "Connection to server failed" << endl;
        closesocket(Sock);
        WSACleanup();
        return false;
    }
    qDebug()<<"Server connect successfully"<<endl;
    return true;
}
bool sessionCreate()
{

    if (libssh2_init(0) != 0) {//libssh2
        cout << "libssh2 initialization failed" << endl;
        closesocket(Sock);
        WSACleanup();
        return false;
    }

    Session = libssh2_session_init(); //ssh
    if (!Session) {
        cout << "Failed to create SSH session" << endl;
        closesocket(Sock);
        WSACleanup();
        return false;
    }

    // ���� SSH ����
    if (libssh2_session_handshake(Session, Sock) != 0) {
        fprintf(stderr, "Failed to establish SSH session\n");
        libssh2_session_free(Session);
        closesocket(Sock);
        WSACleanup();
        return false;
    }

    //֤
    if (libssh2_userauth_password(Session, username.c_str(), password.c_str()) != 0) {
        fprintf(stderr, "Authentication failed\n");
        libssh2_session_disconnect(Session, "Normal Shutdown");
        libssh2_session_free(Session);
        closesocket(Sock);
        WSACleanup();
        return false;
    }

    cout<<" Session sycAuthenticed successfully!"<<endl;

    return true;
}
bool disconnectFromServer()
{
    if(libssh2_session_disconnect(Session, "Normal Shutdown")!=0){
        return false;
    }
    libssh2_session_free(Session);
    if(closesocket(Sock)!=0){
        return false;
    }
    if(WSACleanup()!=0){
        return false;
    }
    cout<<"Disconnected from server."<<endl;
    return true;
}
void cleanAllChannels(){

    for (int i = 0; i < 3; i++) {
        if (ListeningChannel[i]) {
            libssh2_channel_free(ListeningChannel[i]);
        }

    }

}
void createChannels()
{

    string listeningCommands[3]={"tail -f t1.txt","tail -f t2.txt","tail -f t3.txt"};

    for (int i = 0; i < 3; i++) {
        ListeningChannel[i]= libssh2_channel_open_session(Session);
        libssh2_channel_exec( ListeningChannel[i], listeningCommands[i].c_str());
    }

}

void poll_channels() {
    std::vector<LIBSSH2_POLLFD> active_fds;

    // 初始化活跃通道


    for (int i = 0; i < 3; i++) {
        if (ListeningChannel[i]) {
            LIBSSH2_POLLFD fd;
            fd.type = LIBSSH2_POLLFD_CHANNEL;
            fd.fd.channel = ListeningChannel[i];
            fd.events = LIBSSH2_POLLFD_POLLIN;
            active_fds.push_back(fd);
        }
    }

    // 事件循环
    while (!active_fds.empty()) {

        int rc = libssh2_poll(active_fds.data(), active_fds.size(), 10); //  超时时间

        qDebug() << "rc is " << rc;

        //轮询到有events事件发生

        if (rc > 0) {

            for (size_t i = 0; i < active_fds.size();i++ ) {

                if (active_fds[i].revents & LIBSSH2_POLLFD_POLLIN) {
                    // 读取数据
                    char buffer[8096];

                    int bytesRead = libssh2_channel_read(active_fds[i].fd.channel, buffer, sizeof(buffer));

                    if (bytesRead < 0) {
                        qDebug() << "error";
                        libssh2_channel_close(active_fds[i].fd.channel);
                        libssh2_channel_free(active_fds[i].fd.channel);
                        active_fds.erase(active_fds.begin() + i);
                    }
                    else if (bytesRead == 0) {
                        // 通道关闭
                        qDebug() << "bytes==0 closed";
                        libssh2_channel_close(active_fds[i].fd.channel);
                        libssh2_channel_free(active_fds[i].fd.channel);
                        active_fds.erase(active_fds.begin() + i);
                    }
                    else {
                        qDebug() << "read data";
                        buffer[bytesRead] = '\0';
                        printf("ListeningChannel %zu get data is:\n %s", i, buffer);
                        qDebug() << "--------------------------------";
                        //i++; //读取到了数据之后 i++ 之后可以进行下一个channel
                    }
                }

                // 如果通道发生了关闭事件
                else if (active_fds[i].revents & LIBSSH2_POLLFD_CHANNEL_CLOSED) {
                    qDebug() << "Channel " << i << " has closed";
                    libssh2_channel_free(active_fds[i].fd.channel);
                    active_fds.erase(active_fds.begin() + i); //移除元素
                }
                //上诉事件都没有发生 查找下一个通道
                else {
                    qDebug()<<"unknown events";
                   // i++;
                }

            }
        }

        else if (rc == 0) {
            qDebug() << "rc == 0 no events happened";
        }
        else {
            qDebug() << "poll error";
            break;
        }

        Sleep(3000);


    }

    qDebug() << "poll ending";
    // 清理所有通道
    // cleanAllChannels();
}


int main()
{
    qDebug()<<"starting!";
    connectToServer();
    sessionCreate();
    createChannels();
    poll_channels();


    return 0;
}