实战踩坑 代码总结
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;
}