首页 > 解决方案 > 使用 libssh SFTP 下载的文件已损坏

问题描述

我正在使用 libssh 从本地 Windows 机器上的 Debian Linux 服务器下载文件,程序运行没有错误,但下载的文件已损坏。当我通过pscp它下载时,我不知道我是否在缓冲区或其他方面做错了。

生成文件的大小是相同的,当我通过 FileZilla 或 WinSCP 等其他工具下载时,一切顺利。该文件不再损坏。当我运行我的代码时,它会损坏

我正在使用 Visual Studio 2019 在 Windows 10 上运行此代码。在多次弄乱此代码后,我认为问题出在write文件写入功能上,当我在十六进制编辑器中打开生成的文件时,我只看到字节的差异保持不变的文件。

我之前最终发布了 Dart 版本的代码,但 C 版本几乎与 Dart 版本相同。

#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <stdexcept>
#include <string.h>
#include <exception>
#include <fstream>
#include <libssh/callbacks.h>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include "custom_exception.cpp"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <io.h>
#include <time.h>
#include <chrono>

using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;

//using namespace std;
using std::string;
using std::cout;
using std::endl;
using std::cin;


// Good chunk size
#define MAX_XFER_BUF_SIZE 16384
int sftpDownloadFileTo(ssh_session session, const char* fullRemotePath, const char* fullLocalPath)
{
     
    int access_type;
    sftp_file file;
    char buffer[MAX_XFER_BUF_SIZE * 8];//128KB
    ssize_t nbytes, nwritten, rc;
    int fd;
    access_type = O_RDONLY;

     sftp_session sftp = sftp_new(session);
    if (sftp == NULL)
    {
        fprintf(stderr, "Error allocating SFTP session: %s\n",
            ssh_get_error(session));
        return SSH_ERROR;
    }
    rc = sftp_init(sftp);
    if (rc != SSH_OK)
    {
        fprintf(stderr, "Error initializing SFTP session: %d.\n",
            sftp_get_error(sftp));
        sftp_free(sftp);
        return rc;
    }
        

    file = sftp_open(sftp, fullRemotePath, access_type, 0);

    if (file == NULL) {
        fprintf(stderr, "Can't open file for reading: %s\n", ssh_get_error(session));
        return SSH_ERROR;
    }

    fd = open(fullLocalPath, O_CREAT | O_RDWR, 0777);
    if (fd < 0) {
        fprintf(stderr, "Can't open file for writing: %s\n",
            strerror(errno));
        return SSH_ERROR;
    }

    for (;;) {
        nbytes = sftp_read(file, buffer, sizeof(buffer));
        if (nbytes == 0) {
            break; // EOF
        }
        else if (nbytes < 0) {
            fprintf(stderr, "Error while reading file: %s\n",
                ssh_get_error(session));
            sftp_close(file);
            return SSH_ERROR;
        }
        nwritten = write(fd, buffer, nbytes);
        if (nwritten != nbytes) {
            fprintf(stderr, "Error writing: %s\n",
                strerror(errno));
            sftp_close(file);
            return SSH_ERROR;
        }
    }
    rc = sftp_close(file);
    if (rc != SSH_OK) {
        fprintf(stderr, "Can't close the read file: %s\n",
            ssh_get_error(session));
        return rc;
    }

    sftp_free(sftp);
    return SSH_OK;
}

int main()
{

    ssh_session my_ssh_session;
    int rc;
    int port = 22;
    string password = "Ins257257";
    auto host = "192.168.133.13";
    auto username = "isaque.neves";

    int verbosity = SSH_LOG_PROTOCOL;
    // Abra a sessão e defina as opções
    my_ssh_session = ssh_new();
    if (my_ssh_session == NULL)
        exit(-1);
    ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, host);
    //ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
    ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
    // Conecte-se ao servidor
    rc = ssh_connect(my_ssh_session);
    if (rc != SSH_OK)
    {
        
        fprintf(stderr, "Error connecting to host: %s\n",
            ssh_get_error(my_ssh_session));
        exit(-1);
        
    }
    // Autenticar-se

    rc = ssh_userauth_password(my_ssh_session, username, password.c_str());
    if (rc != SSH_AUTH_SUCCESS)
    {
        fprintf(stderr, "Error authenticating with password: %s\n",
            ssh_get_error(my_ssh_session));
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        exit(-1);
    }

    clock_t tic = clock();
    auto t1 = high_resolution_clock::now();
    sftpDownloadFileTo(my_ssh_session, "/home/isaque.neves/go1.11.4.linux-amd64.tar.gz", "D:/MyDartProjects/fsbackup/libssh_binding/go1.11.4.linux-amd64.tar.gz");
    auto t2 = high_resolution_clock::now();
    clock_t toc = clock();
    
    duration<double, std::milli> ms_double = t2 - t1;   
    std::cout << ms_double.count() << " ms\r\n";

    printf("Elapsed: %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC);

    ssh_disconnect(my_ssh_session);
    ssh_free(my_ssh_session);

    std::cout << "End\n";

    return 0;
}

https://github.com/insinfo/fsbackup/tree/main/libssh_binding

标签: c++csftplibssh

解决方案


 fd = open(fullLocalPath, O_CREAT | O_RDWR, 0777);

这是你的问题。由于您在 Windows 上运行,我们需要在此处进行调整。

 fd = open(fullLocalPath, O_CREAT | O_RDWR | O_BINARY, 0777);

否则 write() 将尝试调整行尾。


推荐阅读