当前位置:   article > 正文

Windows VS2017 编译 libssh2 1.7.0(执行命令、文件上传、下载)

libssh2 vs2017 编译

下载安装 OpenSSL

要编译 libssh2,必须先编译好 OpenSSL 的静态库,直接从 http://slproweb.com/products/Win32OpenSSL.html 下载已经编译好的包含 lib 和 include 文件的安装包即可。访问该网站点击下载完整的安装包,注意,不要下载 light 版本,因为 light 版本不带 lib 和 include。如下图:

549050-20190720015530879-2103215469.png

下载完成后直接安装,我这里安装到 D:\OpenSSL-Win32 目录:

549050-20190720015559465-91972123.png

OpenSSL 就这样安装完毕了,如果你按网上自己编译的方法去自己编译,恐怕要耗上你至少半天的时间。我们来看看他的目录结构。

549050-20190720015625034-1759292450.png

开始编译 libssh2
https://www.libssh2.org/snapshots/ 下载最新版本的源码包,解压出来后,用 VS2017 打开libssh2-1.9.0-20190719\win32\libssh2.dsw(其实你可以用任何版本)。

此时会提示升级项目,点击确定升级即可:

549050-20190720015725164-1167326826.png

升级完成后,项目成功加载,里面有两个工程,一个是 libssh2,一个是 tests。tests 是一个测试的项目,我们不用管,我们重点关注的就是 libssh2 项目。

打开 libssh2 的属性管理器,可以看到该项目被官方配置好了已经有很多编译方式:

549050-20190720015749655-65543966.png

因为我们要用 OpenSSL lib 的方式编译,且要 Release 版本的,所以我只用这个做演示,大家自己需要什么版本自己编译即可。首先双击 OpenSSL LIB Release | Win32,编辑该项目属性,在 C/C++ -> 常规 -> 附加包含目录 中,添加 OpenSSL 的 include 路径 D:\OpenSSL-Win32\include,如下图:

549050-20190720015827524-2115526312.png

接下来,添加 OpenSSL 的库路径和库文件到项目中。

  • 选择项目属性中的 库管理器 -> 常规 -> 附加库目录,添加 OpenSSL 的 Lib 库路径 D:\OpenSSL-Win32\lib\VC
  • 选择项目属性中的 库管理器 -> 常规 -> 附加依赖库,添加 OpenSSL 的 Lib 文件 libeay32MT.lib ssleay32MT.lib

这里大家可能注意到了,libeay32.lib 和 ssleay32.lib 分好多个版本,有 MD、MDd、MT、MTd 等,我们到底要选择哪个那?这要取决你编译这个库要使用的 运行库。选择该项目属性中的 C/C++ -> 代码生成 -> 运行库,根据你要调用 libssh2 的项目属性。

549050-20190720015911305-1145403054.png

修改这里的属性,因为我要调用 libssh2 的项目使用的是 多线程MT,所以这里我也选择了 多线程MT,同时,你选择 libeay32.lib 和 ssleay32.lib 的时候,就根据这里的属性选择即可。

至此全部配置完毕了,编译一下项目,遇到了一个其他问题,编译器提示 snprintf 宏重定义:

549050-20190720015948241-922694968.png

这是因为在 libssh2_config.h 中重复定义了 snprintf 宏,只需要将 libssh2_config.h 中的定义注释即可:

549050-20190720020012485-1909015341.png

当然,这不是最终解决方案,在 libssh2 的 github 中,有人曾提出了这个问题,并且目前 github 最新的代码已经解决了这个问题,其解决的办法是判断 VC 库的版本决定是否定义 snprintf 宏。参见:https://github.com/libssh2/libssh2/commit/ded55537acbfda9756667e054c22972842633cf4

注释掉冲突的代码后,再次重新编译项目,这次就可以编译通过了,后面有两条警告,无需理会,不影响我们使用。

  1. 1>------ 已启动生成: 项目: libssh2, 配置: OpenSSL LIB Release Win32 ------
  2. 1> agent.c
  3. 1> channel.c
  4. 1> comp.c
  5. 1> crypt.c
  6. 1> global.c
  7. 1> hostkey.c
  8. 1> keepalive.c
  9. 1> kex.c
  10. 1> knownhost.c
  11. 1> mac.c
  12. 1> misc.c
  13. 1> openssl.c
  14. 1> packet.c
  15. 1> pem.c
  16. 1> publickey.c
  17. 1> scp.c
  18. 1> session.c
  19. 1> sftp.c
  20. 1> transport.c
  21. 1> userauth.c
  22. 1> 正在生成代码...
  23. 1> 正在编译...
  24. 1> version.c
  25. 1> wincng.c
  26. 1> 正在生成代码...
  27. 1>ssleay32MT.lib(SSLEAY32.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR 已在 libeay32MT.lib(LIBEAY32.dll) 中定义;已忽略第二个定义
  28. 1>ssleay32MT.lib(SSLEAY32.dll) : warning LNK4221: 此对象文件未定义任何之前未定义的公共符号,因此任何耗用此库的链接操作都不会使用此文件
  29. 1> libssh2.vcxproj -> D:\libssh2-1.7.0\win32\.\Release_lib\libssh2.lib
  30. ========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0==========

以下是我调试通过的 VS2015 的项目目录,用 VS2015 打开可以直接编译通过的,下载后打开 win32 目录,用 VS2015 打开 libssh2.sln 编译即可:

点击下载 libssh2-1.7.0

测试 libssh2

接下来我们新建一个 Win32 控制台的空项目,新建一个 cpp 文件。

549050-20190720020258051-1512552784.png

然后复制我们刚刚编译好的 libssh2 的库文件和所需的头文件。

  • 在新建的 Win32 项目目录下新建两个目录,一个叫 include,一个叫 lib。
  • 复制我们刚才生成好的 libssh2-1.7.0\win32\Release_lib\libssh2.lib 到新建 Win32 项目的 lib 目录下。
  • 复制 libssh2-1.7.0\include 目录下所有文件到新建的 Win32 项目的 include 目录下。
  • 复制 libssh2-1.7.0\win32\libssh2_config.h 文件到新建的 Win32 项目的 include 目录下。

复制完成后的目录结构如下:

  1. │ libssh2_example.vcxproj
  2. │ libssh2_example.vcxproj.filters
  3. │ main.cpp
  4. ├─include
  5. │ libssh2.h
  6. │ libssh2_config.h
  7. │ libssh2_publickey.h
  8. │ libssh2_sftp.h
  9. └─lib
  10. libssh2.lib

将测试项目的解决方案配置改为 Release,将 include 目录添加到项目的“附加包含目录”中。

549050-20190720020452345-525218922.png

将 lib 目录添加到项目的“附加库目录”中。

549050-20190720020514379-953253219.png

添加 libssh2.lib 到“附加依赖库”中。

549050-20190720020535773-643178584.png

这里项目属性就配置好了,我们到官网找一个测试代码,拷贝到我们的项目里试一下。打开 https://www.libssh2.org/examples,随便找一个例子,我这里找的是 ssh2_exec.c 的列子,选择 ssh2_exec.c 例子,将里面所有的代码复制出来到我们测试项目的 main.cpp 中,然后修改一下例子中连接服务器的 IP 地址、用户名口令等信息。

549050-20190720020611609-764972962.png

编译项目,提示了如下错误:

549050-20190720020632113-273567565.png

在代码的第一行(注意一定是第一行,所有 include 的前面)加上一句 #define _WINSOCK_DEPRECATED_NO_WARNINGS,禁用这个警告。

549050-20190720020655903-1560969036.png

再次编译,提示找不到很多符号的错误:

549050-20190720020909631-351880928.png

这是因为我们使用了 Windows socket 库里面的函数,要包含一下 ws2_32.lib 库文件,一样在附加依赖库中,增加 ws2_32.lib。

549050-20190720020935173-879679353.png

再次编译,这次编译成功了。

549050-20190720021024514-630201723.png

CTRL+F5 运行一下测试项目,就可以看到执行命令的结果输出了。

549050-20190720021050889-1639410644.png

SFTP客户端文件上传、文件下载代码

把libeay32.lib放到自己当前工程目录的lib目录下

549050-20190720023657276-62790427.png

SFTP客户端示例代码:

  1. #include "SFTP_Libssh2.h"
  2. #include <iostream>
  3. int main(int argc, char* argv[])
  4. {
  5. //下面的代码只要在进程初始化的时候执行
  6. kagula::network::SFTP_Init();
  7. //测试SFTP链接
  8. kagula::network::SFTP_Libssh2* client = kagula::network::SFTP_Libssh2::Inst();
  9. std::string ip = "192.168.19.130";
  10. uint16_t port = 22;
  11. std::string usr = "kagula";
  12. std::string pwd = "123456";
  13. if (false == client->IsAbilityConn(ip, port, usr, pwd))
  14. {
  15. std::cout << client->strLastError << std::endl;
  16. return -1;
  17. }
  18. //测试文件上传,d:\\temp\\a.html
  19. if (0 != client->upload(ip, 22, usr, pwd, "d:\\temp\\a.html", "/home/kagula/a.html"))
  20. {
  21. std::cout << "Error:" << client->strLastError << std::endl;
  22. } else
  23. {
  24. std::cout << client->strLastError << std::endl;
  25. }
  26. //测试文件下载
  27. if (0 != client->download(ip, 22, usr, pwd, "/home/kagula/a.html","d:\\temp\\b.html" ))
  28. {
  29. std::cout << "Error:" << client->strLastError << std::endl;
  30. }
  31. else
  32. {
  33. std::cout << client->strLastError << std::endl;
  34. }
  35. //进程准备结束,释放资源的时候,运行下面的代码
  36. kagula::network::SFTP_Exit();
  37. return 0;
  38. }

SFTP_Libssh2.h

  1. #pragma once
  2. #include <string>
  3. #include <atomic>
  4. /*
  5. 功能:SFTP协议的文件传输功能
  6. 最后更新日期:2014-5-17
  7. 简介:借助Libssh2库很容易实现sftp,ssh2客户端,这里给出
  8. 如何实现Sftp客户端的代码
  9. 测试环境:Windows 8.1 64bit、Visual Studio 2013 Professional SP1
  10. OpenSSL 1.0.1g、zlib-1.2.8、libssh2 1.4.3
  11. Win32控制台项目
  12. 注意:动态链接需要把“libssh2.dll”文件复制到当前项目路径下
  13. 说明:原来的代码支持多线程,从应用程序抽出来的时候简化了,
  14. 你可以修改代码使它同时支持上传或下载多个文件。
  15. 建议:[1]第三方库直接下载源代码自己编译免得库由于编译器版本的
  16. 不同或设置的不同链接的时候一大堆麻烦。
  17. [2]读懂代码根据项目需求作相应修改
  18. 补充阅读资料:
  19. 《使用libssh2库实现支持密码参数的ssh2客户端》
  20. http://blog.chinaunix.net/uid-24382173-id-229823.html
  21. */
  22. namespace kagula {
  23. namespace network {
  24. int SFTP_Init();
  25. void SFTP_Exit();
  26. class SFTP_BKCall
  27. {
  28. public:
  29. /* progress返回值范围[0.0,1.0] */
  30. virtual void OnProgress(float progress) = 0;
  31. };
  32. class SFTP_Libssh2
  33. {
  34. public:
  35. static SFTP_Libssh2* Inst()
  36. {
  37. static SFTP_Libssh2 inst;
  38. return &inst;
  39. }
  40. /*
  41. 入口参数使用说明
  42. ip: 就填一个IP地址就好了,例如“127.0.0.1”。
  43. port: 端口,SFTP服务器默认端口为22
  44. username:
  45. password:
  46. sftppath: 远程路径“/”开头 ,例如“/a.jpg”
  47. localpath: 本地路径,例如“d:\\temp\\test.jpg”
  48. strLastError: 错误信息
  49. 出口参数
  50. 返回不等于零,代表失败!
  51. */
  52. int upload(std::string ip, unsigned short port, std::string username,
  53. std::string password, std::string localpath, std::string remotepath);
  54. int download(std::string ip, unsigned short port, std::string username,
  55. std::string password, std::string sftppath, std::string localpath);
  56. //测试SFTP服务器是否可以链接
  57. bool IsAbilityConn(std::string ip, unsigned short port, std::string username,
  58. std::string password);
  59. //设置回掉函数
  60. void SetBKCall(SFTP_BKCall *bkCall) { m_bkCall = bkCall; }
  61. //存放最近的错误信息
  62. std::string strLastError;
  63. //用于停止当前上传或下载线程
  64. void stop() { m_isBreak.store(true); }
  65. private:
  66. SFTP_Libssh2() :m_bkCall(NULL) { m_isBreak.store(false); };//防止直接初始化
  67. SFTP_Libssh2(const SFTP_Libssh2&); //防止拷贝复制
  68. SFTP_Libssh2& operator=(const SFTP_Libssh2&); //防止分配(运算符函数的调用)
  69. SFTP_BKCall *m_bkCall;
  70. std::atomic_bool m_isBreak; //带读写保护的bool值
  71. };
  72. }
  73. }

SFTP_Libssh2.cpp

  1. //SFTP_Libssh2.cpp文件清单
  2. #include "SFTP_Libssh2.h"
  3. #include <libssh2.h>
  4. #include <libssh2_sftp.h>
  5. #ifdef HAVE_WINSOCK2_H
  6. #include <winsock2.h>
  7. #endif
  8. #ifdef HAVE_SYS_SOCKET_H
  9. #include <sys/socket.h>
  10. #endif
  11. #ifdef HAVE_NETINET_IN_H
  12. #include <netinet/in.h>
  13. #endif
  14. #ifdef HAVE_UNISTD_H
  15. #include <unistd.h>
  16. #endif
  17. #ifdef HAVE_ARPA_INET_H
  18. #include <arpa/inet.h>
  19. #endif
  20. #ifdef HAVE_SYS_TIME_H
  21. #include <sys/time.h>
  22. #endif
  23. #include <sys/types.h>
  24. #include <fcntl.h>
  25. #include <errno.h>
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <sstream>
  29. #include <iomanip>
  30. #pragma comment(lib, "ws2_32.lib")
  31. #pragma comment(lib, "libeay32.lib")
  32. #pragma comment(lib, "libssh2.lib")
  33. namespace kagula {
  34. namespace network
  35. {
  36. //初始化进程的时候调用
  37. //如果非0表示初始化失败!
  38. int SFTP_Init()
  39. {
  40. WSADATA wsadata;
  41. int rc = WSAStartup(MAKEWORD(2, 0), &wsadata);
  42. if (rc != 0) {
  43. return rc;
  44. }
  45. rc = libssh2_init(0);
  46. return rc;
  47. }
  48. //进程结束的时候调用
  49. void SFTP_Exit()
  50. {
  51. libssh2_exit();
  52. WSACleanup();
  53. }
  54. bool SFTP_Libssh2::IsAbilityConn(std::string ip, unsigned short port, std::string username,
  55. std::string password)
  56. {
  57. unsigned long hostaddr;
  58. struct sockaddr_in sin;
  59. const char *fingerprint;
  60. LIBSSH2_SESSION *session;
  61. int rc;
  62. bool bR = false;
  63. FILE *local;
  64. LIBSSH2_SFTP *sftp_session;
  65. LIBSSH2_SFTP_HANDLE *sftp_handle;
  66. hostaddr = inet_addr(ip.c_str());//hostaddr = htonl(0x7F000001);
  67. //新建连接
  68. int sock = socket(AF_INET, SOCK_STREAM, 0);
  69. sin.sin_family = AF_INET;
  70. sin.sin_port = htons(port);
  71. sin.sin_addr.s_addr = hostaddr;
  72. if (connect(sock, (struct sockaddr*)(&sin),
  73. sizeof(struct sockaddr_in)) != 0) {
  74. std::ostringstream ostr;
  75. ostr << "[" << __FILE__ << "][" << __LINE__ << "]failed to connect" << ip << "!" << std::endl;
  76. strLastError = ostr.str();
  77. return bR;
  78. }
  79. //新建对话实例
  80. session = libssh2_session_init();
  81. if (!session)
  82. {
  83. closesocket(sock);
  84. return bR;
  85. }
  86. //设置调用阻塞
  87. libssh2_session_set_blocking(session, 1);
  88. //进行握手
  89. rc = libssh2_session_handshake(session, sock);
  90. if (rc) {
  91. std::ostringstream ostr;
  92. ostr << "[" << __FILE__ << "][" << __LINE__ << "]Failure establishing SSH session: " << rc << std::endl;
  93. strLastError = ostr.str();
  94. libssh2_session_free(session); closesocket(sock);
  95. return bR;
  96. }
  97. //检查主机指纹
  98. std::ostringstream ostr;
  99. fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
  100. ostr << "Fingerprint: ";
  101. for (int i = 0; i < 20; i++) {
  102. unsigned char c = fingerprint[i];
  103. int nT = c;
  104. ostr << std::hex << std::setw(2) << std::setfill('0') << nT;
  105. }
  106. strLastError = ostr.str();
  107. //通过密码验证登陆用户身份
  108. if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
  109. std::ostringstream ostr;
  110. ostr << "[" << __FILE__ << "][" << __LINE__ << "]Authentication by password failed." << std::endl;
  111. strLastError = ostr.str();
  112. goto shutdown;
  113. }
  114. sftp_session = libssh2_sftp_init(session);
  115. if (!sftp_session) {
  116. std::ostringstream ostr;
  117. ostr << "[" << __FILE__ << "][" << __LINE__ << "]Unable to init SFTP session " << std::endl;
  118. strLastError = ostr.str();
  119. goto shutdown;
  120. }
  121. bR = true;
  122. libssh2_sftp_shutdown(sftp_session);
  123. shutdown:
  124. libssh2_session_disconnect(session,
  125. "Normal Shutdown, Thank you for playing");
  126. libssh2_session_free(session);
  127. closesocket(sock);
  128. return bR;
  129. }
  130. /*
  131. 源码参考地址
  132. http://www.libssh2.org/examples/sftp_write.html
  133. */
  134. int SFTP_Libssh2::upload(std::string ip, unsigned short port, std::string username, std::string password,
  135. std::string localpath, std::string remotepath)
  136. {
  137. if (ip.length()<1 || username.length()<1 || password.length()<1 || localpath.length()<1 || remotepath.length()<1)
  138. {
  139. return -1;
  140. }
  141. int nR = 0;
  142. unsigned long hostaddr;
  143. struct sockaddr_in sin;
  144. const char *fingerprint;
  145. LIBSSH2_SESSION *session;
  146. int rc = -1;
  147. FILE *local = NULL;
  148. LIBSSH2_SFTP *sftp_session;
  149. LIBSSH2_SFTP_HANDLE *sftp_handle;
  150. hostaddr = inet_addr(ip.c_str());//hostaddr = htonl(0x7F000001);
  151. if (fopen_s(&local, localpath.c_str(), "rb") != 0) {
  152. std::ostringstream ostr;
  153. ostr << "[" << __FILE__ << "][" << __LINE__ << "]Can't open local file " << localpath << std::endl;
  154. strLastError = ostr.str();
  155. return -2;
  156. }
  157. //取待上传文件整个size.
  158. fseek(local, 0, SEEK_END);
  159. size_t filesize = ftell(local);//local file大小,在readFromDisk中被引用
  160. fseek(local, 0, SEEK_SET);//文件指针重置到文件头
  161. //新建连接
  162. int sock = socket(AF_INET, SOCK_STREAM, 0);
  163. sin.sin_family = AF_INET;
  164. sin.sin_port = htons(port);
  165. sin.sin_addr.s_addr = hostaddr;
  166. if (connect(sock, (struct sockaddr*)(&sin),
  167. sizeof(struct sockaddr_in)) != 0) {
  168. std::ostringstream ostr;
  169. ostr << "[" << __FILE__ << "][" << __LINE__ << "] failed to connect " << ip << std::endl;
  170. strLastError = ostr.str();
  171. fclose(local);
  172. return -3;
  173. }
  174. //创建会话实例
  175. session = libssh2_session_init();
  176. if (!session)
  177. {
  178. fclose(local); closesocket(sock);
  179. return -4;
  180. }
  181. //阻塞方式调用libssh2
  182. libssh2_session_set_blocking(session, 1);
  183. //进行握手
  184. rc = libssh2_session_handshake(session, sock);
  185. if (rc) {
  186. std::ostringstream ostr;
  187. ostr << "[" << __FILE__ << "][" << __LINE__ << "] Failure establishing SSH session:" << rc << std::endl;
  188. strLastError = ostr.str();
  189. fclose(local); libssh2_session_free(session); closesocket(sock);
  190. return -5;
  191. }
  192. //获取主机指纹
  193. std::ostringstream ostr;
  194. fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
  195. ostr << "Fingerprint: ";
  196. for (int i = 0; i < 20; i++) {
  197. unsigned char c = fingerprint[i];
  198. int nT = c;//这样转是为了防止符号位扩展
  199. ostr << std::hex << std::setw(2) << std::setfill('0') << nT;
  200. }
  201. strLastError = ostr.str();
  202. //通过密码验证
  203. if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
  204. std::ostringstream ostr;
  205. ostr << "[" << __FILE__ << "][" << __LINE__ << "] Authentication by password failed ["
  206. << username << "][" << password << "]" << rc << std::endl;
  207. strLastError = ostr.str();
  208. goto shutdown;
  209. }
  210. sftp_session = libssh2_sftp_init(session);
  211. if (!sftp_session) {
  212. std::ostringstream ostr;
  213. ostr << "[" << __FILE__ << "][" << __LINE__ << "] Unable to init SFTP session" << std::endl;
  214. strLastError = ostr.str();
  215. goto shutdown;
  216. }
  217. //向SFTP服务器发出新建文件请求
  218. sftp_handle =
  219. libssh2_sftp_open(sftp_session, remotepath.c_str(),
  220. LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
  221. LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR |
  222. LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH);
  223. if (!sftp_handle) {
  224. std::ostringstream ostr;
  225. ostr << "[" << __FILE__ << "][" << __LINE__ << "] Unable to open file with SFTP. ip="
  226. << ip <<"] remotepath=[" << remotepath << "]" << std::endl;
  227. strLastError = ostr.str();
  228. nR = -1;
  229. goto shutdown;
  230. }
  231. char mem[1024 * 16];
  232. size_t nread;
  233. char *ptr;
  234. size_t count = 0;
  235. do {
  236. nread = fread(mem, 1, sizeof(mem), local);
  237. if (nread <= 0) {
  238. //到达文件尾部
  239. break;
  240. }
  241. ptr = mem;
  242. do {
  243. // 向服务器写数据,直到数据写完毕
  244. rc = libssh2_sftp_write(sftp_handle, ptr, nread);
  245. if (rc < 0)
  246. break;
  247. ptr += rc; count += nread;
  248. nread -= rc;
  249. //如果设置了回调,进行回调
  250. if (m_bkCall)
  251. {
  252. float p = count / (float)filesize;
  253. m_bkCall->OnProgress(p);
  254. }
  255. //callback.end
  256. } while (nread);
  257. if ( m_isBreak.load() == true )
  258. {
  259. std::ostringstream ostr;
  260. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 上传文件任务被用户break!" << std::endl;
  261. strLastError = ostr.str();
  262. nR = -6;
  263. break;
  264. }
  265. } while (rc > 0);
  266. libssh2_sftp_close(sftp_handle);
  267. libssh2_sftp_shutdown(sftp_session);
  268. shutdown:
  269. libssh2_session_disconnect(session,
  270. "Normal Shutdown, Thank you for playing");
  271. libssh2_session_free(session);
  272. closesocket(sock);
  273. fclose(local);
  274. return nR;//返回“0”表示成功
  275. }
  276. /*
  277. 源码参考地址
  278. http://www.oschina.net/code/snippet_12_10717
  279. */
  280. int SFTP_Libssh2::download(std::string ip, unsigned short port, std::string username, std::string password,
  281. std::string sftppath, std::string localpath)
  282. {
  283. unsigned long hostaddr;
  284. int sock, i, auth_pw = 0;
  285. struct sockaddr_in sin;
  286. const char *fingerprint;
  287. char *userauthlist;
  288. LIBSSH2_SESSION *session;
  289. int rc;
  290. LIBSSH2_SFTP *sftp_session;
  291. LIBSSH2_SFTP_HANDLE *sftp_handle;
  292. hostaddr = inet_addr(ip.c_str()); //hostaddr = htonl(0x7F000001);
  293. /*
  294. * The application code is responsible for creating the socket
  295. * and establishing the connection
  296. */
  297. sock = socket(AF_INET, SOCK_STREAM, 0);
  298. sin.sin_family = AF_INET;
  299. sin.sin_port = htons(port);
  300. sin.sin_addr.s_addr = hostaddr;
  301. if (connect(sock, (struct sockaddr*)(&sin),
  302. sizeof(struct sockaddr_in)) != 0) {
  303. std::ostringstream ostr;
  304. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 连接失败!" << std::endl;
  305. strLastError = ostr.str();
  306. return -1;
  307. }
  308. /* Create a session instance
  309. */
  310. session = libssh2_session_init();
  311. if (!session)
  312. return -1;
  313. /* Since we have set non-blocking, tell libssh2 we are blocking */
  314. libssh2_session_set_blocking(session, 1);
  315. /* ... start it up. This will trade welcome banners, exchange keys,
  316. * and setup crypto, compression, and MAC layers
  317. */
  318. rc = libssh2_session_handshake(session, sock);
  319. if (rc) {
  320. std::ostringstream ostr;
  321. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 建立SSH会话失败" << rc << std::endl;
  322. strLastError = ostr.str();
  323. return -1;
  324. }
  325. /* At this point we havn't yet authenticated. The first thing to do
  326. * is check the hostkey's fingerprint against our known hosts Your app
  327. * may have it hard coded, may go to a file, may present it to the
  328. * user, that's your call
  329. */
  330. fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
  331. std::ostringstream ostr;
  332. fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
  333. ostr << "Fingerprint: ";
  334. for (int i = 0; i < 20; i++) {
  335. unsigned char c = fingerprint[i];
  336. int nT = c;
  337. ostr << std::hex << std::setw(2) << std::setfill('0') << nT;
  338. }
  339. strLastError = ostr.str();
  340. /* check what authentication methods are available */
  341. userauthlist = libssh2_userauth_list(session, username.c_str(), username.length());
  342. if (strstr(userauthlist, "password") == NULL)
  343. {
  344. std::ostringstream ostr;
  345. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 服务器不支持输入password方式验证!" << std::endl;
  346. strLastError = ostr.str();
  347. goto shutdown;
  348. }
  349. /* We could authenticate via password */
  350. if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
  351. std::ostringstream ostr;
  352. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 密码错误!" << std::endl;
  353. strLastError = ostr.str();
  354. goto shutdown;
  355. }
  356. sftp_session = libssh2_sftp_init(session);
  357. if (!sftp_session) {
  358. std::ostringstream ostr;
  359. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 初始化FTL对话失败!" << std::endl;
  360. strLastError = ostr.str();
  361. goto shutdown;
  362. }
  363. /* Request a file via SFTP */
  364. sftp_handle =
  365. libssh2_sftp_open(sftp_session, sftppath.c_str(), LIBSSH2_FXF_READ, 0);
  366. if (!sftp_handle) {
  367. std::ostringstream ostr;
  368. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 打开文件失败! " << libssh2_sftp_last_error(sftp_session) << std::endl;
  369. strLastError = ostr.str();
  370. goto shutdown;
  371. }
  372. FILE *stream;
  373. if (fopen_s(&stream, localpath.c_str(), "wb") == 0)
  374. {
  375. do {
  376. char mem[1024];
  377. /* loop until we fail */
  378. rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
  379. if (rc > 0) {
  380. //从内存到磁盘
  381. fwrite(mem, 1, rc, stream);
  382. }
  383. else {
  384. break;
  385. }
  386. } while (1);
  387. fclose(stream);
  388. }
  389. else {
  390. std::ostringstream ostr;
  391. ostr << "[" << __FILE__ << "][" << __LINE__ << "] 新建本地文件失败 " << localpath << std::endl;
  392. strLastError = ostr.str();
  393. }
  394. libssh2_sftp_close(sftp_handle);
  395. libssh2_sftp_shutdown(sftp_session);
  396. shutdown:
  397. libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
  398. libssh2_session_free(session);
  399. closesocket(sock);//INVALID_SOCKET
  400. return 0;
  401. }
  402. }
  403. }

源码下载

链接:https://pan.baidu.com/s/1OBAw-B5zrITXVDFiIDm_pA
提取码:q25a

参考

Windows VS2015 编译 libssh2 1.7.0

https://www.mycode.net.cn/language/cpp/1681.html

转载于:https://www.cnblogs.com/17bdw/p/11216448.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/894717
推荐阅读
相关标签
  

闽ICP备14008679号