2023年12月3日发(作者:)
SFTP客户端代码示例参考链接:操作系统:Windows7/8,VS2013环境:libssh2 1.4.3、zlib-1.2.8、openssl-1.0.1g原文:C:Program Files (x86)Microsoft VisualStudio 12.0VClib提示找不到ws2_或,添加下面的链接路径C:Program Files (x86)MicrosoftSDKsWindowsv7.1ALib编译通过后文件输出到libssh2-1.4.3win32Release_lib路径下”更新:文件位置:libssh2-1.4.3libssh2-1.4.3win32zlib的头文件是zlib.h,库文件是:nssl的头文件是:opensslconf.h,库文件是:,b的头文件(zlib.h)位置:libssh2-1.4.3ztezlib-1.2.5,库文件()位置:libssh2-1.4.3zteopenssl-1.0.0b staticlibDebugopenssl头文件(opensslconf.h)位置:libssh2-1.4.3zteopenssl-1.0.1lincludeopenssl,库文件(,)位置:libssh2-1.4.3zteopenssl-1.0.0b staticlibDebug 分两个步骤:1.先编译输出(1)配置好zlib和openssl的头文件和库文件链接位置后,编译libssh2项目即可,这时可以把tests项目卸载,反正用不到嘛;编译成功后,输出到libssh2-1.4.3win32Release_lib路径下,(ps:我这里生成的是,我把文件名改为后可以正常使用)2.执行客户端,进行下载图片;新建个项目,把下文三个文件拷贝到项目中,配置libssh2.h,链接位置后,即可执行成功;注意:路径及文件名不能含有中文,否则会报错;下面是SFTP客户端示例代码:三个文件的下载地址:(密码:1qhf) 1 #include "SFTP_Libssh2.h" 2 #include
4 int 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";15 if (false == client->IsAbilityConn(ip, port, usr, pwd))16 {17 std::cout << client->strLastError << std::endl;18 return -1;19 }20
21 //测试文件上传,d:22 if (0 != client->upload(ip, 22, usr, pwd, "d:", "/home/kagula/"))23 {24 std::cout << "Error:" << client->strLastError << std::endl;25 } else26 {27 std::cout << client->strLastError << std::endl;28 }29
30
31 //测试文件下载32 if (0 != client->download(ip, 22, usr, pwd, "/home/kagula/","d:" ))33 {34 std::cout << "Error:" << client->strLastError << std::endl;35 }36 else37 {38 std::cout << client->strLastError << std::endl;39 }40
41 //进程准备结束,释放资源的时候,运行下面的代码42 kagula::network::SFTP_Exit();43 return 0;44 }
SFTP_Libssh2.h 1 #pragma once 2
3 #include
6 /* 7 功能:SFTP协议的文件传输功能 8 最后更新日期:2014-5-17 9 简介:借助Libssh2库很容易实现sftp,ssh2客户端,这里给出10 如何实现Sftp客户端的代码11 测试环境:Windows 8.1 64bit、Visual Studio 2013 Professional SP112 OpenSSL 1.0.1g、zlib-1.2.8、libssh2 1.4.313 Win32控制台项目14 注意:动态链接需要把“”文件复制到当前项目路径下15 说明:原来的代码支持多线程,从应用程序抽出来的时候简化了,16 你可以修改代码使它同时支持上传或下载多个文件。17 建议:[1]第三方库直接下载源代码自己编译免得库由于编译器版本的18 不同或设置的不同链接的时候一大堆麻烦。19 [2]读懂代码根据项目需求作相应修改20 补充阅读资料:21 《使用libssh2库实现支持密码参数的ssh2客户端》22 /23 */24 namespace kagula {25 namespace network {26 int SFTP_Init();27 void SFTP_Exit();28
29 class SFTP_BKCall30 {31 public:32 /* progress返回值范围[0.0,1.0] */33 virtual void OnProgress(float progress) = 0;34 };35
36 class SFTP_Libssh237 {38 public:39 static SFTP_Libssh2* Inst()40 {41 static SFTP_Libssh2 inst;42
43 return &inst;44 }45
46 /*47 入口参数使用说明48 ip: 就填一个IP地址就好了,例如“127.0.0.1”。49 port: 端口,SFTP服务器默认端口为22。50 username:51 password:52 sftppath: 远程路径“/”开头 ,例如“/”53 localpath: 本地路径,例如“d:”54 strLastError: 错误信息55 出口参数56 返回不等于零,代表失败!57 */58 int upload(std::string ip, unsigned short port, std::string username,59 std::string password, std::string localpath, std::string remotepath);60 int download(std::string ip, unsigned short port, std::string username,61 std::string password, std::string sftppath, std::string localpath);62
63 //测试SFTP服务器是否可以链接64 bool IsAbilityConn(std::string ip, unsigned short port, std::string username,65 std::string password);66
67 //设置回掉函数68 void SetBKCall(SFTP_BKCall *bkCall) { m_bkCall = bkCall; }69
70 //存放最近的错误信息71 std::string strLastError;72
73 //用于停止当前上传或下载线程74 void stop() { m_(true); }75 private:76 SFTP_Libssh2() :m_bkCall(NULL) { m_(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_ 1 //SFTP_文件清单 2 #include "SFTP_Libssh2.h" 3
4 #include
7 #ifdef HAVE_WINSOCK2_H 8 #include
26 #include
32 #include
35 #pragma comment(lib, "ws2_") 36
37 #pragma comment(lib, "")
38 #pragma comment(lib, "")
39
40 namespace kagula { 41 namespace network 42 { 43 //初始化进程的时候调用 44 //如果非0表示初始化失败! 45 int SFTP_Init() 46 { 47 WSADATA wsadata; 48 int rc = WSAStartup(MAKEWORD(2, 0), &wsadata); 49 if (rc != 0) { 50 return rc; 51 } 52
53 rc = libssh2_init(0); 54
55 return rc; 56 } 57
58 //进程结束的时候调用 59 void SFTP_Exit() 60 { 61 libssh2_exit(); 62
63 WSACleanup(); 64 } 65
66 bool SFTP_Libssh2::IsAbilityConn(std::string ip, unsigned short port, std::string username, 67 std::string password) 68 { 69 unsigned long hostaddr; 70 struct sockaddr_in sin; 71 const char *fingerprint; 72 LIBSSH2_SESSION *session; 73 int rc; 74 bool 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 //新建连接 83 int sock = socket(AF_INET, SOCK_STREAM, 0); 84
85 _family = AF_INET; 86 _port = htons(port); 87 _addr.s_addr = hostaddr; 88 if (connect(sock, (struct sockaddr*)(&sin), 89 sizeof(struct sockaddr_in)) != 0) { 90 std::ostringstream ostr; 91 ostr << "[" << __FILE__ << "][" << __LINE__ << "]failed to connect" << ip << "!" << std::endl; 92 strLastError = (); 93
94 return bR; 95 } 96
97 //新建对话实例 98 session = libssh2_session_init(); 99 if (!session)100 {101 closesocket(sock);102 return bR;103 }104
105 //设置调用阻塞106 libssh2_session_set_blocking(session, 1);107
108 //进行握手109 rc = libssh2_session_handshake(session, sock);110 if (rc) {111 std::ostringstream ostr;112 ostr << "[" << __FILE__ << "][" << __LINE__ << "]Failure establishing SSH session: " << rc << std::endl;113 strLastError = ();114
115 libssh2_session_free(session); closesocket(sock);116 return bR;117 }118
119 //检查主机指纹120 std::ostringstream ostr;121 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);122 ostr << "Fingerprint: ";123 for (int i = 0; i < 20; i++) {124 unsigned char c = fingerprint[i];125 int nT = c;126 ostr << std::hex << std::setw(2) << std::setfill('0') << nT;127 }128 strLastError = ();129
130 //通过密码验证登陆用户身份131 if (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 = ();135 goto shutdown;136 }137 138 sftp_session = libssh2_sftp_init(session);139
140 if (!sftp_session) {141 std::ostringstream ostr;142 ostr << "[" << __FILE__ << "][" << __LINE__ << "]Unable to init SFTP session " << std::endl;143 strLastError = ();144
145 goto 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);158 return bR;159 }160
161 /*162 源码参考地址163 /examples/sftp_164 */165 int SFTP_Libssh2::upload(std::string ip, unsigned short port, std::string username, std::string password,166 std::string localpath, std::string remotepath)167 {168 if (()<1 || ()<1 || ()<1 || ()<1 || ()<1)169 {170 return -1;171 }172
173 int nR = 0;174 unsigned long hostaddr;175 struct sockaddr_in sin;176 const char *fingerprint;177 LIBSSH2_SESSION *session;178 int 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
185 if (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 = ();189
190 return -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 //新建连接199 int sock = socket(AF_INET, SOCK_STREAM, 0);200
201 _family = AF_INET;202 _port = htons(port);203 _addr.s_addr = hostaddr;204 if (connect(sock, (struct sockaddr*)(&sin),205 sizeof(struct sockaddr_in)) != 0) {206 std::ostringstream ostr;207 ostr << "[" << __FILE__ << "][" << __LINE__ << "] failed to connect " << ip << std::endl;208 strLastError = ();209
210 fclose(local);211 return -3;212 }213
214
215 //创建会话实例216 session = libssh2_session_init();217 if (!session)218 {219 fclose(local); closesocket(sock);220 return -4;221 }222
223 //阻塞方式调用libssh2224 libssh2_session_set_blocking(session, 1);225
226 //进行握手227 rc = libssh2_session_handshake(session, sock);228 if (rc) {229 std::ostringstream ostr;230 ostr << "[" << __FILE__ << "][" << __LINE__ << "] Failure establishing SSH session:" << rc << std::endl;231 strLastError = ();232
233 fclose(local); libssh2_session_free(session); closesocket(sock);234 return -5;235 }236
237 //获取主机指纹238 std::ostringstream ostr;239 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);240 ostr << "Fingerprint: ";241 for (int i = 0; i < 20; i++) {242 unsigned char c = fingerprint[i];243 int nT = c;//这样转是为了防止符号位扩展244 ostr << std::hex << std::setw(2) << std::setfill('0') << nT;245 }246 strLastError = ();247
248 //通过密码验证249 if (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 = ();254
255 goto shutdown;256 }257
258 sftp_session = libssh2_sftp_init(session);259
260 if (!sftp_session) {261 std::ostringstream ostr;262 ostr << "[" << __FILE__ << "][" << __LINE__ << "] Unable to init SFTP session" << std::endl;263 strLastError = ();264
265 goto 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
275 if (!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 = ();280
281 nR = -1;282
283 goto shutdown;284 }285
286
287 char mem[1024 * 16];288 size_t nread;289 char *ptr;290 size_t count = 0;291
292 do {293 nread = fread(mem, 1, sizeof(mem), local);294 if (nread <= 0) {295 //到达文件尾部296 break;297 }298 ptr = mem;299 do {300 // 向服务器写数据,直到数据写完毕301 rc = libssh2_sftp_write(sftp_handle, ptr, nread);302 if (rc < 0)303 break;304 ptr += rc; count += nread;305 nread -= rc;306
307 //如果设置了回调,进行回调308 if (m_bkCall)309 {310 float p = count / (float)filesize;311 m_bkCall->OnProgress(p);312 }313 //314 } while (nread);315
316 if ( m_() == true )317 {318 std::ostringstream ostr;319 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 上传文件任务被用户break!" << std::endl;320 strLastError = ();321
322 nR = -6;323 break;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
339 return nR;//返回“0”表示成功340 }341
342 /*343 源码参考地址344 /code/snippet_12_10717345 */346 int 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;350 int sock, i, auth_pw = 0;351 struct sockaddr_in sin;352 const char *fingerprint;353 char *userauthlist;354 LIBSSH2_SESSION *session;355 int 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 socket363 * and establishing the connection364 */365 sock = socket(AF_INET, SOCK_STREAM, 0);366
367 _family = AF_INET;368 _port = htons(port);369 _addr.s_addr = hostaddr;370 if (connect(sock, (struct sockaddr*)(&sin),371 sizeof(struct sockaddr_in)) != 0) {372 std::ostringstream ostr;373 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 连接失败!" << std::endl;374 strLastError = ();375 return -1;376 }377
378 /* Create a session instance379 */380 session = libssh2_session_init();381
382 if (!session)383 return -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 layers391 */392 rc = libssh2_session_handshake(session, sock);393
394 if (rc) {395 std::ostringstream ostr;396 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 建立SSH会话失败" << rc << std::endl;397 strLastError = ();398
399 return -1;400 }401
402 /* At this point we havn't yet authenticated. The first thing to do403 * is check the hostkey's fingerprint against our known hosts Your app404 * may have it hard coded, may go to a file, may present it to the405 * user, that's your call406 */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: ";412 for (int i = 0; i < 20; i++) {413 unsigned char c = fingerprint[i];414 int nT = c;415 ostr << std::hex << std::setw(2) << std::setfill('0') << nT;416 }417 strLastError = ();418
419 /* check what authentication methods are available */420 userauthlist = libssh2_userauth_list(session, username.c_str(), ());421 if (strstr(userauthlist, "password") == NULL)422 {423 std::ostringstream ostr;424 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 服务器不支持输入password方式验证!" << std::endl;425 strLastError = ();426 goto shutdown;427 }428
429 /* We could authenticate via password */430 if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {431
432 std::ostringstream ostr;433 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 密码错误!" << std::endl;434 strLastError = ();435 goto shutdown;436 }437
438 sftp_session = libssh2_sftp_init(session);439 if (!sftp_session) {440 std::ostringstream ostr;441 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 初始化FTL对话失败!" << std::endl;442 strLastError = ();443 goto 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
451 if (!sftp_handle) {452 std::ostringstream ostr;453 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 打开文件失败! " << libssh2_sftp_last_error(sftp_session) << std::endl;454 strLastError = ();455
456 goto shutdown;457 }458
459 FILE *stream;460 if (fopen_s(&stream, localpath.c_str(), "wb") == 0)461 {462 do {463 char mem[1024];464
465 /* loop until we fail */466 rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));467
468 if (rc > 0) {469 //从内存到磁盘470 fwrite(mem, 1, rc, stream);471 }472 else {473 break;474 }475 } while (1);476
477 fclose(stream);478 }479 else {480 std::ostringstream ostr;481 ostr << "[" << __FILE__ << "][" << __LINE__ << "] 新建本地文件失败 " << localpath << std::endl;482 strLastError = ();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_SOCKET495
496 return 0;497 }498 }499 }


发布评论