You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Libssh:ssh_channel_read返回0且ssh_channel_is_open返回false问题求助

嘿,我刚梳理了你遇到的libssh通道问题——虽然你已经搞定了SSH连接和认证,但通道一直没真正打开、读操作返回0的原因其实很明确,咱们一步步拆解问题,再给你修复后的完整读写代码:

问题分析

你遇到的核心问题是:创建ssh_channel后没有发起会话请求。libssh的ssh_channel_new()只是在本地实例化了一个通道对象,必须通过ssh_channel_open_session()与服务器完成通道握手,通道才会真正处于打开状态,才能进行读写操作。

原问题代码

#include <libssh/libssh.h>
#include <iostream>
#include <string>

int main() {
    ssh_session my_ssh_session = ssh_new();
    if (my_ssh_session == nullptr) {
        std::cerr << "Failed to create SSH session" << std::endl;
        return 1;
    }

    // 设置连接参数
    ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "raspberrypi.local");
    ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "pi");

    // 连接服务器
    int rc = ssh_connect(my_ssh_session);
    if (rc != SSH_OK) {
        std::cerr << "Connection failed: " << ssh_get_error(my_ssh_session) << std::endl;
        ssh_free(my_ssh_session);
        return 1;
    }

    // 密码认证
    rc = ssh_userauth_password(my_ssh_session, nullptr, "your_password");
    if (rc != SSH_OK) {
        std::cerr << "Authentication failed: " << ssh_get_error(my_ssh_session) << std::endl;
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        return 1;
    }
    std::cout << "Authentication successful!" << std::endl;

    // 创建通道
    ssh_channel channel = ssh_channel_new(my_ssh_session);
    if (channel == nullptr) {
        std::cerr << "Failed to create channel" << std::endl;
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        return 1;
    }

    // 这里缺少了ssh_channel_open_session()调用!
    std::cout << "Channel is open? " << (ssh_channel_is_open(channel) ? "Yes" : "No") << std::endl;

    char buffer[1024];
    int nbytes;
    nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
    std::cout << "Bytes read: " << nbytes << std::endl;

    // 清理资源
    ssh_channel_free(channel);
    ssh_disconnect(my_ssh_session);
    ssh_free(my_ssh_session);
    return 0;
}

编译命令与原运行输出

编译命令

g++ -o ssh_test ssh_test.cpp -lssh

运行输出

Authentication successful!
Channel is open? No
Bytes read: 0

修复后的可用代码(含完整读写功能)

我已经补上了关键的会话打开步骤,同时实现了向服务器发送命令并读取返回结果的功能:

#include <libssh/libssh.h>
#include <iostream>
#include <string>
#include <cstring>

int main() {
    ssh_session my_ssh_session = ssh_new();
    if (my_ssh_session == nullptr) {
        std::cerr << "Failed to create SSH session" << std::endl;
        return 1;
    }

    // 设置连接参数
    ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "raspberrypi.local");
    ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "pi");

    // 连接服务器
    int rc = ssh_connect(my_ssh_session);
    if (rc != SSH_OK) {
        std::cerr << "Connection failed: " << ssh_get_error(my_ssh_session) << std::endl;
        ssh_free(my_ssh_session);
        return 1;
    }

    // 密码认证
    rc = ssh_userauth_password(my_ssh_session, nullptr, "your_password");
    if (rc != SSH_OK) {
        std::cerr << "Authentication failed: " << ssh_get_error(my_ssh_session) << std::endl;
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        return 1;
    }
    std::cout << "Authentication successful!" << std::endl;

    // 创建通道
    ssh_channel channel = ssh_channel_new(my_ssh_session);
    if (channel == nullptr) {
        std::cerr << "Failed to create channel" << std::endl;
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        return 1;
    }

    // 关键步骤:打开会话通道
    rc = ssh_channel_open_session(channel);
    if (rc != SSH_OK) {
        std::cerr << "Failed to open session channel: " << ssh_get_error(my_ssh_session) << std::endl;
        ssh_channel_free(channel);
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        return 1;
    }
    std::cout << "Channel is open? " << (ssh_channel_is_open(channel) ? "Yes" : "No") << std::endl;

    // 向服务器发送命令(示例:获取系统信息)
    std::string command = "uname -a\n";
    rc = ssh_channel_write(channel, command.c_str(), command.size());
    if (rc < 0) {
        std::cerr << "Failed to write to channel: " << ssh_get_error(my_ssh_session) << std::endl;
        ssh_channel_close(channel);
        ssh_channel_free(channel);
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        return 1;
    }
    std::cout << "Sent " << rc << " bytes to server" << std::endl;

    // 发送EOF标记,告诉服务器没有更多数据要发送
    ssh_channel_send_eof(channel);

    // 循环读取服务器返回的结果
    char buffer[1024];
    int nbytes;
    std::cout << "\nServer response:\n";
    while ((nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
        std::cout.write(buffer, nbytes);
    }
    if (nbytes < 0) {
        std::cerr << "\nError reading from channel: " << ssh_get_error(my_ssh_session) << std::endl;
    }

    // 按顺序清理资源:先关闭通道,再释放会话
    ssh_channel_close(channel);
    ssh_channel_free(channel);
    ssh_disconnect(my_ssh_session);
    ssh_free(my_ssh_session);
    return 0;
}

核心修复点说明

  1. 添加ssh_channel_open_session():这是通道真正激活的关键,必须在创建通道后调用,否则通道只是本地空对象,不会和服务器建立会话连接。
  2. 完善读写流程:发送命令后调用ssh_channel_send_eof()告知服务器数据发送完毕,这样服务器才会返回完整的命令输出;同时用循环读取数据,避免遗漏分段返回的内容。
  3. 规范资源清理:确保通道先关闭再释放,会话先断开再释放,避免内存泄漏或资源残留。

内容的提问来源于stack exchange,提问作者marko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:41:58