SFTP客户端代码示例
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SFTP客户端代码⽰例
参考链接:
操作系统:Windows7/8,VS2013
环境:libssh2 1.4.3、zlib-1.2.8、openssl-1.0.1g
原⽂:
C:\Program Files (x86)\Microsoft VisualStudio 12.0\VC\lib
提⽰找不到ws2_32.lib或odbc32.lib,添加下⾯的链接路径
C:\Program Files (x86)\MicrosoftSDKs\Windows\v7.1A\Lib
编译通过后⽂件输出到\libssh2-1.4.3\win32\Release_lib路径下”
更新:
libssh2.dsw⽂件位置:\libssh2-1.4.3\libssh2-1.4.3\win32
zlib的头⽂件是zlib.h,库⽂件是:zlib.lib
openssl的头⽂件是:opensslconf.h,库⽂件是:libeay32.lib,ssleay32.lib
zlib的头⽂件(zlib.h)位置:\libssh2-1.4.3\zte\zlib-1.2.5,库⽂件(zlib.lib)位置:\libssh2-1.4.3\zte\openssl-1.0.0b staticlib\Debug openssl头⽂件(opensslconf.h)位置:\libssh2-1.4.3\zte\openssl-1.0.1l\include\openssl,库⽂件(libeay32.lib,ssleay32.lib)位
置:\libssh2-1.4.3\zte\openssl-1.0.0b staticlib\Debug
分两个步骤:
1.先编译输出libssh
2.lib
(1)配置好zlib和openssl的头⽂件和库⽂件链接位置后,编译libssh2项⽬即可,这时可以把tests项⽬卸载,反正⽤不到嘛;
编译成功后,输出libssh2.lib到\libssh2-1.4.3\win32\Release_lib路径下,(ps:我这⾥⽣成的是libssh2d.lib,我把⽂件名改为libssh2.lib后可以正常使⽤)
2.执⾏客户端,进⾏下载图⽚;
新建个项⽬,把下⽂三个⽂件拷贝到项⽬中,配置libssh2.h,libssh2.lib链接位置后,即可执⾏成功;
注意:路径及⽂件名不能含有中⽂,否则会报错;
下⾯是SFTP客户端⽰例代码:
三个⽂件的下载地址:(密码:1qhf)
main.cpp
1 #include "SFTP_Libssh2.h"
2 #include <iostream>
3
4int main(int argc, char* argv[])
5 {
6//下⾯的代码只要在进程初始化的时候执⾏
7 kagula::network::SFTP_Init();
8
9//测试SFTP链接
10 kagula::network::SFTP_Libssh2* client = kagula::network::SFTP_Libssh2::Inst();
11 std::string ip = "192.168.19.130";
12 uint16_t port = 22;
13 std::string usr = "kagula";
14 std::string pwd = "123456";
15if (false == client->IsAbilityConn(ip, port, usr, pwd))
16 {
17 std::cout << client->strLastError << std::endl;
18return -1;
19 }
20
21//测试⽂件上传,d:\\temp\\a.html
22if (0 != client->upload(ip, 22, usr, pwd, "d:\\temp\\a.html", "/home/kagula/a.html"))
23 {
24 std::cout << "Error:" << client->strLastError << std::endl;
25 } else
26 {
27 std::cout << client->strLastError << std::endl;
28 }
29
30
31//测试⽂件下载
32if (0 != client->download(ip, 22, usr, pwd, "/home/kagula/a.html","d:\\temp\\b.html" ))
33 {
34 std::cout << "Error:" << client->strLastError << std::endl;
35 }
36else
37 {
38 std::cout << client->strLastError << std::endl;
39 }
40
41//进程准备结束,释放资源的时候,运⾏下⾯的代码
42 kagula::network::SFTP_Exit();
43return0;
44 }
SFTP_Libssh2.h
1#pragma once
2
3 #include <string>
4 #include <atomic>
5
6/*
7功能:SFTP协议的⽂件传输功能
8最后更新⽇期:2014-5-17
9简介:借助Libssh2库很容易实现sftp,ssh2客户端,这⾥给出
10如何实现Sftp客户端的代码
11测试环境:Windows 8.1 64bit、Visual Studio 2013 Professional SP1
12 OpenSSL 1.0.1g、zlib-1.2.8、libssh2 1.4.3
13 Win32控制台项⽬
14注意:动态链接需要把“libssh2.dll”⽂件复制到当前项⽬路径下
15说明:原来的代码⽀持多线程,从应⽤程序抽出来的时候简化了,
16你可以修改代码使它同时⽀持上传或下载多个⽂件。
17建议:[1]第三⽅库直接下载源代码⾃⼰编译免得库由于编译器版本的
18不同或设置的不同链接的时候⼀⼤堆⿇烦。
19 [2]读懂代码根据项⽬需求作相应修改
20补充阅读资料:
21《使⽤libssh2库实现⽀持密码参数的ssh2客户端》
22/uid-24382173-id-229823.html
23*/
24namespace kagula {
25namespace network {
26int SFTP_Init();
27void SFTP_Exit();
28
29class SFTP_BKCall
30 {
31public:
32/* progress返回值范围[0.0,1.0] */
33virtual void OnProgress(float progress) = 0;
34 };
35
36class SFTP_Libssh2
37 {
38public:
39static SFTP_Libssh2* Inst()
40 {
41static SFTP_Libssh2 inst;
42
43return &inst;
44 }
45
46/*
47⼊⼝参数使⽤说明
48 ip: 就填⼀个IP地址就好了,例如“127.0.0.1”。
49 port: 端⼝,SFTP服务器默认端⼝为22。
50 username:
51 password:
52 sftppath: 远程路径“/”开头,例如“/a.jpg”
53 localpath: 本地路径,例如“d:\\temp\\test.jpg”
54 strLastError: 错误信息
55出⼝参数
56返回不等于零,代表失败!
57*/
58int upload(std::string ip, unsigned short port, std::string username,
59 std::string password, std::string localpath, std::string remotepath);
60int download(std::string ip, unsigned short port, std::string username,
61 std::string password, std::string sftppath, std::string localpath);
62
63//测试SFTP服务器是否可以链接
64bool IsAbilityConn(std::string ip, unsigned short port, std::string username,
65 std::string password);
66
67//设置回掉函数
68void SetBKCall(SFTP_BKCall *bkCall) { m_bkCall = bkCall; }
69
70//存放最近的错误信息
71 std::string strLastError;
72
73//⽤于停⽌当前上传或下载线程
74void stop() { m_isBreak.store(true); }
75private:
76 SFTP_Libssh2() :m_bkCall(NULL) { m_isBreak.store(false); };//防⽌直接初始化
77 SFTP_Libssh2(const SFTP_Libssh2&); //防⽌拷贝复制
78 SFTP_Libssh2& operator=(const SFTP_Libssh2&); //防⽌分配(运算符函数的调⽤) 79
80 SFTP_BKCall *m_bkCall;
81 std::atomic_bool m_isBreak; //带读写保护的bool值
82 };
83 }
84 }
SFTP_Libssh2.cpp
1//SFTP_Libssh2.cpp⽂件清单
2 #include "SFTP_Libssh2.h"
3
4 #include <libssh2.h>
5 #include <libssh2_sftp.h>
6
7 #ifdef HAVE_WINSOCK2_H
8 #include <winsock2.h>
9#endif
10 #ifdef HAVE_SYS_SOCKET_H
11 #include <sys/socket.h>
12#endif
13 #ifdef HAVE_NETINET_IN_H
14 #include <netinet/in.h>
15#endif
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18#endif
19 #ifdef HAVE_ARPA_INET_H
20 #include <arpa/inet.h>
21#endif
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24#endif
25
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <ctype.h>
31
32 #include <sstream>
33 #include <iomanip>
34
35#pragma comment(lib, "ws2_32.lib")
36
37#pragma comment(lib, "libeay32.lib")
38#pragma comment(lib, "libssh2.lib")
39
40namespace kagula {
41namespace network
42 {
43//初始化进程的时候调⽤
44//如果⾮0表⽰初始化失败!
45int SFTP_Init()
46 {
47 WSADATA wsadata;
48int rc = WSAStartup(MAKEWORD(2, 0), &wsadata);
49if (rc != 0) {
50return rc;
51 }
52
53 rc = libssh2_init(0);
54
55return rc;
56 }
57
58//进程结束的时候调⽤
59void SFTP_Exit()
60 {
61 libssh2_exit();
62
63 WSACleanup();
64 }
65
66bool SFTP_Libssh2::IsAbilityConn(std::string ip, unsigned short port, std::string username,
67 std::string password)
68 {
69 unsigned long hostaddr;
70struct sockaddr_in sin;
71const char *fingerprint;
72 LIBSSH2_SESSION *session;
73int rc;
74bool bR = false;
75 FILE *local;
76 LIBSSH2_SFTP *sftp_session;
77 LIBSSH2_SFTP_HANDLE *sftp_handle;
78
79 hostaddr = inet_addr(ip.c_str());//hostaddr = htonl(0x7F000001);
80
81
82//新建连接
83int sock = socket(AF_INET, SOCK_STREAM, 0);
84
85 sin.sin_family = AF_INET;
86 sin.sin_port = htons(port);
87 sin.sin_addr.s_addr = hostaddr;
88if (connect(sock, (struct sockaddr*)(&sin),
89sizeof(struct sockaddr_in)) != 0) {
90 std::ostringstream ostr;
91 ostr << "[" << __FILE__ << "][" << __LINE__ << "]failed to connect" << ip << "!" << std::endl;
92 strLastError = ostr.str();
93
94return bR;
95 }
96
97//新建对话实例
98 session = libssh2_session_init();
99if (!session)
100 {
101 closesocket(sock);
102return bR;
103 }
104
105//设置调⽤阻塞
106 libssh2_session_set_blocking(session, 1);
107
108//进⾏握⼿
109 rc = libssh2_session_handshake(session, sock);
110if (rc) {
111 std::ostringstream ostr;
112 ostr << "[" << __FILE__ << "][" << __LINE__ << "]Failure establishing SSH session: " << rc << std::endl; 113 strLastError = ostr.str();
114
115 libssh2_session_free(session); closesocket(sock);
116return bR;
117 }
118
119//检查主机指纹
120 std::ostringstream ostr;
121 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
122 ostr << "Fingerprint: ";
123for (int i = 0; i < 20; i++) {
124 unsigned char c = fingerprint[i];
125int nT = c;
126 ostr << std::hex << std::setw(2) << std::setfill('0') << nT;
127 }
128 strLastError = ostr.str();
129
130//通过密码验证登陆⽤户⾝份
131if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
132 std::ostringstream ostr;
133 ostr << "[" << __FILE__ << "][" << __LINE__ << "]Authentication by password failed." << std::endl;
134 strLastError = ostr.str();
135goto shutdown;
136 }
137
138 sftp_session = libssh2_sftp_init(session);
139
140if (!sftp_session) {
141 std::ostringstream ostr;
142 ostr << "[" << __FILE__ << "][" << __LINE__ << "]Unable to init SFTP session " << std::endl;
143 strLastError = ostr.str();
144
145goto shutdown;
146 }
147
148 bR = true;
149
150
151 libssh2_sftp_shutdown(sftp_session);
152
153 shutdown:
154 libssh2_session_disconnect(session,
155"Normal Shutdown, Thank you for playing");
156 libssh2_session_free(session);
157 closesocket(sock);
158return bR;
159 }
160
161/*
162源码参考地址
163/examples/sftp_write.html
164*/
165int SFTP_Libssh2::upload(std::string ip, unsigned short port, std::string username, std::string password,
166 std::string localpath, std::string remotepath)
167 {
168if (ip.length()<1 || username.length()<1 || password.length()<1 || localpath.length()<1 || remotepath.length()<1) 169 {
170return -1;
171 }
172
173int nR = 0;
174 unsigned long hostaddr;
175struct sockaddr_in sin;
176const char *fingerprint;
177 LIBSSH2_SESSION *session;
178int rc = -1;
179 FILE *local = NULL;
180 LIBSSH2_SFTP *sftp_session;
181 LIBSSH2_SFTP_HANDLE *sftp_handle;
182
183 hostaddr = inet_addr(ip.c_str());//hostaddr = htonl(0x7F000001);
184
185if (fopen_s(&local, localpath.c_str(), "rb") != 0) {
186 std::ostringstream ostr;
187 ostr << "[" << __FILE__ << "][" << __LINE__ << "]Can't open local file " << localpath << std::endl;
188 strLastError = ostr.str();
189
190return -2;
191 }
192
193//取待上传⽂件整个size.
194 fseek(local, 0, SEEK_END);
195 size_t filesize = ftell(local);//local file⼤⼩,在readFromDisk中被引⽤
196 fseek(local, 0, SEEK_SET);//⽂件指针重置到⽂件头
197
198//新建连接
199int sock = socket(AF_INET, SOCK_STREAM, 0);
200
201 sin.sin_family = AF_INET;
202 sin.sin_port = htons(port);
203 sin.sin_addr.s_addr = hostaddr;
204if (connect(sock, (struct sockaddr*)(&sin),
205sizeof(struct sockaddr_in)) != 0) {
206 std::ostringstream ostr;
207 ostr << "[" << __FILE__ << "][" << __LINE__ << "] failed to connect " << ip << std::endl;
208 strLastError = ostr.str();
209
210 fclose(local);
211return -3;
212 }
213
214
215//创建会话实例
216 session = libssh2_session_init();
217if (!session)
218 {
219 fclose(local); closesocket(sock);
220return -4;
221 }
223//阻塞⽅式调⽤libssh2
224 libssh2_session_set_blocking(session, 1);
225
226//进⾏握⼿
227 rc = libssh2_session_handshake(session, sock);
228if (rc) {
229 std::ostringstream ostr;
230 ostr << "[" << __FILE__ << "][" << __LINE__ << "] Failure establishing SSH session:" << rc << std::endl; 231 strLastError = ostr.str();
232
233 fclose(local); libssh2_session_free(session); closesocket(sock);
234return -5;
235 }
236
237//获取主机指纹
238 std::ostringstream ostr;
239 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
240 ostr << "Fingerprint: ";
241for (int i = 0; i < 20; i++) {
242 unsigned char c = fingerprint[i];
243int nT = c;//这样转是为了防⽌符号位扩展
244 ostr << std::hex << std::setw(2) << std::setfill('0') << nT;
245 }
246 strLastError = ostr.str();
247
248//通过密码验证
249if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
250 std::ostringstream ostr;
251 ostr << "[" << __FILE__ << "][" << __LINE__ << "] Authentication by password failed ["
252 << username << "][" << password << "]" << rc << std::endl;
253 strLastError = ostr.str();
254
255goto shutdown;
256 }
257
258 sftp_session = libssh2_sftp_init(session);
259
260if (!sftp_session) {
261 std::ostringstream ostr;
262 ostr << "[" << __FILE__ << "][" << __LINE__ << "] Unable to init SFTP session" << std::endl;
263 strLastError = ostr.str();
264
265goto shutdown;
266 }
267
268//向SFTP服务器发出新建⽂件请求
269 sftp_handle =
270 libssh2_sftp_open(sftp_session, remotepath.c_str(),
271 LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
272 LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR |
273 LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH);
274
275if (!sftp_handle) {
276 std::ostringstream ostr;
277 ostr << "[" << __FILE__ << "][" << __LINE__ << "] Unable to open file with SFTP. ip="
278 << ip <<"] remotepath=[" << remotepath << "]" << std::endl;
279 strLastError = ostr.str();
280
281 nR = -1;
282
283goto shutdown;
284 }
285
286
287char mem[1024 * 16];
288 size_t nread;
289char *ptr;
290 size_t count = 0;
291
292do {
293 nread = fread(mem, 1, sizeof(mem), local);
294if (nread <= 0) {
295//到达⽂件尾部
296break;
297 }
298 ptr = mem;
299do {
300// 向服务器写数据,直到数据写完毕
301 rc = libssh2_sftp_write(sftp_handle, ptr, nread);
302if (rc < 0)
303break;
304 ptr += rc; count += nread;
305 nread -= rc;
307//如果设置了回调,进⾏回调
308if (m_bkCall)
309 {
310float p = count / (float)filesize;
311 m_bkCall->OnProgress(p);
312 }
313//callback.end
314 } while (nread);
315
316if ( m_isBreak.load() == true )
317 {
318 std::ostringstream ostr;
319 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 上传⽂件任务被⽤户break!" << std::endl;
320 strLastError = ostr.str();
321
322 nR = -6;
323break;
324 }
325 } while (rc > 0);
326
327 libssh2_sftp_close(sftp_handle);
328 libssh2_sftp_shutdown(sftp_session);
329
330 shutdown:
331 libssh2_session_disconnect(session,
332"Normal Shutdown, Thank you for playing");
333 libssh2_session_free(session);
334
335 closesocket(sock);
336
337 fclose(local);
338
339return nR;//返回“0”表⽰成功
340 }
341
342/*
343源码参考地址
344/code/snippet_12_10717
345*/
346int SFTP_Libssh2::download(std::string ip, unsigned short port, std::string username, std::string password, 347 std::string sftppath, std::string localpath)
348 {
349 unsigned long hostaddr;
350int sock, i, auth_pw = 0;
351struct sockaddr_in sin;
352const char *fingerprint;
353char *userauthlist;
354 LIBSSH2_SESSION *session;
355int rc;
356 LIBSSH2_SFTP *sftp_session;
357 LIBSSH2_SFTP_HANDLE *sftp_handle;
358
359 hostaddr = inet_addr(ip.c_str()); //hostaddr = htonl(0x7F000001);
360
361/*
362 * The application code is responsible for creating the socket
363 * and establishing the connection
364*/
365 sock = socket(AF_INET, SOCK_STREAM, 0);
366
367 sin.sin_family = AF_INET;
368 sin.sin_port = htons(port);
369 sin.sin_addr.s_addr = hostaddr;
370if (connect(sock, (struct sockaddr*)(&sin),
371sizeof(struct sockaddr_in)) != 0) {
372 std::ostringstream ostr;
373 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 连接失败!" << std::endl;
374 strLastError = ostr.str();
375return -1;
376 }
377
378/* Create a session instance
379*/
380 session = libssh2_session_init();
381
382if (!session)
383return -1;
384
385/* Since we have set non-blocking, tell libssh2 we are blocking */
386 libssh2_session_set_blocking(session, 1);
387
388
389/* ... start it up. This will trade welcome banners, exchange keys,
390 * and setup crypto, compression, and MAC layers
391*/
392 rc = libssh2_session_handshake(session, sock);
393
394if (rc) {
395 std::ostringstream ostr;
396 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 建⽴SSH会话失败" << rc << std::endl;
397 strLastError = ostr.str();
398
399return -1;
400 }
401
402/* At this point we havn't yet authenticated. The first thing to do
403 * is check the hostkey's fingerprint against our known hosts Your app
404 * may have it hard coded, may go to a file, may present it to the
405 * user, that's your call
406*/
407 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
408
409 std::ostringstream ostr;
410 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
411 ostr << "Fingerprint: ";
412for (int i = 0; i < 20; i++) {
413 unsigned char c = fingerprint[i];
414int nT = c;
415 ostr << std::hex << std::setw(2) << std::setfill('0') << nT;
416 }
417 strLastError = ostr.str();
418
419/* check what authentication methods are available */
420 userauthlist = libssh2_userauth_list(session, username.c_str(), username.length());
421if (strstr(userauthlist, "password") == NULL)
422 {
423 std::ostringstream ostr;
424 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 服务器不⽀持输⼊password⽅式验证!" << std::endl;
425 strLastError = ostr.str();
426goto shutdown;
427 }
428
429/* We could authenticate via password */
430if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
431
432 std::ostringstream ostr;
433 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 密码错误!" << std::endl;
434 strLastError = ostr.str();
435goto shutdown;
436 }
437
438 sftp_session = libssh2_sftp_init(session);
439if (!sftp_session) {
440 std::ostringstream ostr;
441 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 初始化FTL对话失败!" << std::endl;
442 strLastError = ostr.str();
443goto shutdown;
444 }
445
446/* Request a file via SFTP */
447 sftp_handle =
448 libssh2_sftp_open(sftp_session, sftppath.c_str(), LIBSSH2_FXF_READ, 0);
449
450
451if (!sftp_handle) {
452 std::ostringstream ostr;
453 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 打开⽂件失败! " << libssh2_sftp_last_error(sftp_session) << std::endl; 454 strLastError = ostr.str();
455
456goto shutdown;
457 }
458
459 FILE *stream;
460if (fopen_s(&stream, localpath.c_str(), "wb") == 0)
461 {
462do {
463char mem[1024];
464
465/* loop until we fail */
466 rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
467
468if (rc > 0) {
469//从内存到磁盘
470 fwrite(mem, 1, rc, stream);
471 }
472else {
473break;
474 }
475 } while (1);
476
477 fclose(stream);
478 }
479else {
480 std::ostringstream ostr;
481 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 新建本地⽂件失败 " << localpath << std::endl; 482 strLastError = ostr.str();
483 }
484
485 libssh2_sftp_close(sftp_handle);
486
487 libssh2_sftp_shutdown(sftp_session);
488
489 shutdown:
490
491 libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
492 libssh2_session_free(session);
493
494 closesocket(sock);//INVALID_SOCKET
495
496return0;
497 }
498 }
499 }。