如何使用 Qt/QNetworkAccessManager (C++) 实现 SFTP
Posted
技术标签:
【中文标题】如何使用 Qt/QNetworkAccessManager (C++) 实现 SFTP【英文标题】:Howto implement SFTP with Qt/QNetworkAccessManager (C++) 【发布时间】:2011-07-20 06:58:25 【问题描述】:我是 Qt 新手,我想为我的软件实现 FTP 和 SFTP 支持。 当我用谷歌搜索时,我发现不存在 Qt 的 sftp 库,但使用 QNetworkAccessManager 应该是可能的。 然后我试图发现如何构建自定义协议或类似的东西,但没有弄清楚如何去做。
有人知道我该怎么做吗?
谢谢, 迈克尔
【问题讨论】:
你的目标操作系统是什么,你想如何使用SFTP? 我可以建议自己实现,依赖libssh。 【参考方案1】:Qt SDK 中不支持 SFTP,但 Qt Creator 实现了 SFTP。
我已经隔离了包含 SSH 和 SFTP 的库,并在 Github 中创建了一个名为 QSsh 的新项目。该项目的目的是为任何 Qt 应用程序提供 SSH 和 SFTP 支持。
我写了一个关于如何使用 SFTP 上传文件的示例。看看examples/SecureUploader/
希望对你有帮助
【讨论】:
嗨,你能帮我看看如何将这个库安装到 Qt 吗?【参考方案2】:您需要为每个协议自定义实现。但是我们可以创建一个像 QHttp 这样的类来做到这一点。有几个协议具有相似的语义,但不是全部。所以,如果你想写,告诉我,我帮你。
【讨论】:
不知道我是否很快有空闲时间,但也许我会尝试一下:) 谢谢你的回答【参考方案3】:Qt SDK 中没有当前的 SSH 包装器实现。您有 3 个选择:
-
使用 IETF RFC 和标准草案(如 RFC4253)推出您自己的自定义 SSH/SFTP 客户端实施。这可能不是您想要的。
直接使用任何 ssh 实现库,如 openssh/libssh,或编写自己的 Qt/C++ 包装器以供将来重用。任何需要 ssh 的合理项目通常都链接到一个已经建立的 ssh 库并以编程方式使用它。就像 Qt Creator 所做的那样,如果你深入挖掘它,你会发现前面提到的用户 Paglian。依赖库比自行开发库的风险更小,也更有前瞻性。
直接在命令行界面使用 openssh 工具,使用 QProcess,就像在 shell 中使用它一样。如果您正在处理概念验证项目并且不需要任何复杂的 ftp 操作,这是最快的方法,因为围绕 CLI 工具设计一个强大的包装器可能会有点困难。
【讨论】:
【参考方案4】:我使用 libssh 执行此操作。非常直截了当。 https://api.libssh.org/stable/libssh_tutor_sftp.html
不要忘记将您的 sftp 服务器添加到系统中的已知主机中。
ssh-keyscan -H mysftpserver.com >> ~/.ssh/known_hosts
示例代码:
#include "sftpuploader.h"
#include <QtDebug>
#include <QFileInfo>
#include <libssh/libssh.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <libssh/sftp.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <QFile>
int verify_knownhost(ssh_session session)
int state, hlen;
unsigned char *hash = NULL;
char *hexa;
char buf[10];
state = ssh_is_server_known(session);
hlen = ssh_get_pubkey_hash(session, &hash);
if (hlen < 0)
return -1;
switch (state)
case SSH_SERVER_KNOWN_OK:
break; /* ok */
case SSH_SERVER_KNOWN_CHANGED:
fprintf(stderr, "Host key for server changed: it is now:\n");
ssh_print_hexa("Public key hash", hash, hlen);
fprintf(stderr, "For security reasons, connection will be stopped\n");
free(hash);
return -1;
case SSH_SERVER_FOUND_OTHER:
fprintf(stderr, "The host key for this server was not found but an other"
"type of key exists.\n");
fprintf(stderr, "An attacker might change the default server key to"
"confuse your client into thinking the key does not exist\n");
free(hash);
return -1;
case SSH_SERVER_FILE_NOT_FOUND:
fprintf(stderr, "Could not find known host file.\n");
fprintf(stderr, "If you accept the host key here, the file will be"
"automatically created.\n");
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
case SSH_SERVER_NOT_KNOWN:
hexa = ssh_get_hexa(hash, hlen);
fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
fprintf(stderr, "Public key hash: %s\n", hexa);
free(hexa);
if (fgets(buf, sizeof(buf), stdin) == NULL)
free(hash);
return -1;
if (strncasecmp(buf, "yes", 3) != 0)
free(hash);
return -1;
if (ssh_write_knownhost(session) < 0)
fprintf(stderr, "Error %s\n", strerror(errno));
free(hash);
return -1;
break;
case SSH_SERVER_ERROR:
fprintf(stderr, "Error %s", ssh_get_error(session));
free(hash);
return -1;
free(hash);
return 0;
bool upload(const QString &localFile,
const QString &dest,
const QString &host,
const QString &username,
const QString &passwd)
bool retVal = false;
QFileInfo info(localFile);
m_localFilename = info.canonicalFilePath();
m_remoteFilename = dest + "/" + info.fileName();
int verbosity = SSH_LOG_PROTOCOL;
int port = 22;
int rc;
sftp_session sftp;
sftp_file file;
int access_type;
int nwritten;
QByteArray dataToWrite;
ssh_session my_ssh_session;
QFile myfile(m_localFilename);
if(!myfile.exists())
qDebug() << "SFTPUploader: File doesn't exist " << m_localFilename;
return retVal;
my_ssh_session = ssh_new();
if(my_ssh_session == NULL)
return retVal;
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, host.toUtf8());
ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
qDebug() << "SFTPUploader: Error connecting to localhost: " << ssh_get_error(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
else
qDebug() << "SFTPUploader: SSH connected";
// Verify the server's identity
// For the source code of verify_knowhost(), check previous example
if (verify_knownhost(my_ssh_session) < 0)
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
qDebug() << "SFTPUploader: verify_knownhost failed";
return retVal;
rc = ssh_userauth_password(my_ssh_session, username.toUtf8(), passwd.toUtf8());
if (rc != SSH_AUTH_SUCCESS)
qDebug() << "SFTPUploader: Error authenticating with password: " << ssh_get_error(my_ssh_session);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
else
qDebug() << "SFTPUploader: Authentication sucess";
sftp = sftp_new(my_ssh_session);
if (sftp == NULL)
qDebug() << "SFTPUploader: Error allocating SFTP session:" << ssh_get_error(my_ssh_session);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
rc = sftp_init(sftp);
if (rc != SSH_OK)
qDebug() << "SFTPUploader: Error initializing SFTP session:", sftp_get_error(sftp);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
access_type = O_WRONLY | O_CREAT | O_TRUNC;
file = sftp_open(sftp, dest.toUtf8(), access_type, S_IRWXU);
if (file == NULL)
qDebug() << "SFTPUploader: Can't open file for writing:", ssh_get_error(my_ssh_session);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
if(myfile.open(QFile::ReadOnly))
dataToWrite = myfile.readAll();
nwritten = sftp_write(file, dataToWrite, dataToWrite.size());
if (nwritten != dataToWrite.size())
qDebug() << "SFTPUploader: Can't write data to file: ", ssh_get_error(my_ssh_session);
sftp_close(file);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
rc = sftp_close(file);
if (rc != SSH_OK)
qDebug() << "SFTPUploader: Can't close the written file:" << ssh_get_error(my_ssh_session);
sftp_free(sftp);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return retVal;
else
qDebug() << "SFTPUploader: Success";
retVal = true;
return retVal;
【讨论】:
以上是关于如何使用 Qt/QNetworkAccessManager (C++) 实现 SFTP的主要内容,如果未能解决你的问题,请参考以下文章
如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]
如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?