参考链接:SFTP客户端代码示例

操作系统:Windows7/8,VS2013

环境:libssh2 1.4.3、zlib-1.2.8、openssl-1.0.1g

原文:

“从http://www.libssh2.org/下载libssh2-1.4.3.tar.gz文件,解压后打开libssh2.dsw文件升级项目到VisualStudio 2013,里面有两个项目,只要编译libssh2项目就可以了。编译前需要添加zlib和openssl的头文件和库文件链接位置,如果编译libssh2提示找不到msvcrt.lib,为链接库添加下面的路径

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路径下”

更新:

http://www.libssh2.org/网址访问不通,故换个方式下载了libssh2-1.4.3.tar.gz文件,下载地址:百度网盘(密码:2hwo)

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.先编译输出libssh2.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

 #include "SFTP_Libssh2.h"
#include <iostream> int main(int argc, char* argv[])
{
//下面的代码只要在进程初始化的时候执行
kagula::network::SFTP_Init(); //测试SFTP链接
kagula::network::SFTP_Libssh2* client = kagula::network::SFTP_Libssh2::Inst();
std::string ip = "192.168.19.130";
uint16_t port = ;
std::string usr = "kagula";
std::string pwd = "";
if (false == client->IsAbilityConn(ip, port, usr, pwd))
{
std::cout << client->strLastError << std::endl;
return -;
} //测试文件上传,d:\\temp\\a.html
if ( != client->upload(ip, , usr, pwd, "d:\\temp\\a.html", "/home/kagula/a.html"))
{
std::cout << "Error:" << client->strLastError << std::endl;
} else
{
std::cout << client->strLastError << std::endl;
} //测试文件下载
if ( != client->download(ip, , usr, pwd, "/home/kagula/a.html","d:\\temp\\b.html" ))
{
std::cout << "Error:" << client->strLastError << std::endl;
}
else
{
std::cout << client->strLastError << std::endl;
} //进程准备结束,释放资源的时候,运行下面的代码
kagula::network::SFTP_Exit();
return ;
}

SFTP_Libssh2.h

 #pragma once

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

SFTP_Libssh2.cpp

 //SFTP_Libssh2.cpp文件清单
#include "SFTP_Libssh2.h" #include <libssh2.h>
#include <libssh2_sftp.h> #ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif #include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h> #include <sstream>
#include <iomanip> #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "libssh2.lib") namespace kagula {
namespace network
{
//初始化进程的时候调用
//如果非0表示初始化失败!
int SFTP_Init()
{
WSADATA wsadata;
int rc = WSAStartup(MAKEWORD(, ), &wsadata);
if (rc != ) {
return rc;
} rc = libssh2_init(); return rc;
} //进程结束的时候调用
void SFTP_Exit()
{
libssh2_exit(); WSACleanup();
} bool SFTP_Libssh2::IsAbilityConn(std::string ip, unsigned short port, std::string username,
std::string password)
{
unsigned long hostaddr;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
int rc;
bool bR = false;
FILE *local;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle; hostaddr = inet_addr(ip.c_str());//hostaddr = htonl(0x7F000001); //新建连接
int sock = socket(AF_INET, SOCK_STREAM, ); sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != ) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "]failed to connect" << ip << "!" << std::endl;
strLastError = ostr.str(); return bR;
} //新建对话实例
session = libssh2_session_init();
if (!session)
{
closesocket(sock);
return bR;
} //设置调用阻塞
libssh2_session_set_blocking(session, ); //进行握手
rc = libssh2_session_handshake(session, sock);
if (rc) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "]Failure establishing SSH session: " << rc << std::endl;
strLastError = ostr.str(); libssh2_session_free(session); closesocket(sock);
return bR;
} //检查主机指纹
std::ostringstream ostr;
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
ostr << "Fingerprint: ";
for (int i = ; i < ; i++) {
unsigned char c = fingerprint[i];
int nT = c;
ostr << std::hex << std::setw() << std::setfill('') << nT;
}
strLastError = ostr.str(); //通过密码验证登陆用户身份
if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "]Authentication by password failed." << std::endl;
strLastError = ostr.str();
goto shutdown;
} sftp_session = libssh2_sftp_init(session); if (!sftp_session) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "]Unable to init SFTP session " << std::endl;
strLastError = ostr.str(); goto shutdown;
} bR = true; libssh2_sftp_shutdown(sftp_session); shutdown:
libssh2_session_disconnect(session,
"Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
closesocket(sock);
return bR;
} /*
源码参考地址
http://www.libssh2.org/examples/sftp_write.html
*/
int SFTP_Libssh2::upload(std::string ip, unsigned short port, std::string username, std::string password,
std::string localpath, std::string remotepath)
{
if (ip.length()< || username.length()< || password.length()< || localpath.length()< || remotepath.length()<)
{
return -;
} int nR = ;
unsigned long hostaddr;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
int rc = -;
FILE *local = NULL;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle; hostaddr = inet_addr(ip.c_str());//hostaddr = htonl(0x7F000001); if (fopen_s(&local, localpath.c_str(), "rb") != ) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "]Can't open local file " << localpath << std::endl;
strLastError = ostr.str(); return -;
} //取待上传文件整个size.
fseek(local, , SEEK_END);
size_t filesize = ftell(local);//local file大小,在readFromDisk中被引用
fseek(local, , SEEK_SET);//文件指针重置到文件头 //新建连接
int sock = socket(AF_INET, SOCK_STREAM, ); sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != ) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] failed to connect " << ip << std::endl;
strLastError = ostr.str(); fclose(local);
return -;
} //创建会话实例
session = libssh2_session_init();
if (!session)
{
fclose(local); closesocket(sock);
return -;
} //阻塞方式调用libssh2
libssh2_session_set_blocking(session, ); //进行握手
rc = libssh2_session_handshake(session, sock);
if (rc) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] Failure establishing SSH session:" << rc << std::endl;
strLastError = ostr.str(); fclose(local); libssh2_session_free(session); closesocket(sock);
return -;
} //获取主机指纹
std::ostringstream ostr;
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
ostr << "Fingerprint: ";
for (int i = ; i < ; i++) {
unsigned char c = fingerprint[i];
int nT = c;//这样转是为了防止符号位扩展
ostr << std::hex << std::setw() << std::setfill('') << nT;
}
strLastError = ostr.str(); //通过密码验证
if (libssh2_userauth_password(session, username.c_str(), password.c_str())) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] Authentication by password failed ["
<< username << "][" << password << "]" << rc << std::endl;
strLastError = ostr.str(); goto shutdown;
} sftp_session = libssh2_sftp_init(session); if (!sftp_session) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] Unable to init SFTP session" << std::endl;
strLastError = ostr.str(); goto shutdown;
} //向SFTP服务器发出新建文件请求
sftp_handle =
libssh2_sftp_open(sftp_session, remotepath.c_str(),
LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR |
LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH); if (!sftp_handle) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] Unable to open file with SFTP. ip="
<< ip <<"] remotepath=[" << remotepath << "]" << std::endl;
strLastError = ostr.str(); nR = -; goto shutdown;
} char mem[ * ];
size_t nread;
char *ptr;
size_t count = ; do {
nread = fread(mem, , sizeof(mem), local);
if (nread <= ) {
//到达文件尾部
break;
}
ptr = mem;
do {
// 向服务器写数据,直到数据写完毕
rc = libssh2_sftp_write(sftp_handle, ptr, nread);
if (rc < )
break;
ptr += rc; count += nread;
nread -= rc; //如果设置了回调,进行回调
if (m_bkCall)
{
float p = count / (float)filesize;
m_bkCall->OnProgress(p);
}
//callback.end
} while (nread); if ( m_isBreak.load() == true )
{
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 上传文件任务被用户break!" << std::endl;
strLastError = ostr.str(); nR = -;
break;
}
} while (rc > ); libssh2_sftp_close(sftp_handle);
libssh2_sftp_shutdown(sftp_session); shutdown:
libssh2_session_disconnect(session,
"Normal Shutdown, Thank you for playing");
libssh2_session_free(session); closesocket(sock); fclose(local); return nR;//返回“0”表示成功
} /*
源码参考地址
http://www.oschina.net/code/snippet_12_10717
*/
int SFTP_Libssh2::download(std::string ip, unsigned short port, std::string username, std::string password,
std::string sftppath, std::string localpath)
{
unsigned long hostaddr;
int sock, i, auth_pw = ;
struct sockaddr_in sin;
const char *fingerprint;
char *userauthlist;
LIBSSH2_SESSION *session;
int rc;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle; hostaddr = inet_addr(ip.c_str()); //hostaddr = htonl(0x7F000001); /*
* The application code is responsible for creating the socket
* and establishing the connection
*/
sock = socket(AF_INET, SOCK_STREAM, ); sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != ) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 连接失败!" << std::endl;
strLastError = ostr.str();
return -;
} /* Create a session instance
*/
session = libssh2_session_init(); if (!session)
return -; /* Since we have set non-blocking, tell libssh2 we are blocking */
libssh2_session_set_blocking(session, ); /* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
rc = libssh2_session_handshake(session, sock); if (rc) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 建立SSH会话失败" << rc << std::endl;
strLastError = ostr.str(); return -;
} /* At this point we havn't yet authenticated. The first thing to do
* is check the hostkey's fingerprint against our known hosts Your app
* may have it hard coded, may go to a file, may present it to the
* user, that's your call
*/
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); std::ostringstream ostr;
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
ostr << "Fingerprint: ";
for (int i = ; i < ; i++) {
unsigned char c = fingerprint[i];
int nT = c;
ostr << std::hex << std::setw() << std::setfill('') << nT;
}
strLastError = ostr.str(); /* check what authentication methods are available */
userauthlist = libssh2_userauth_list(session, username.c_str(), username.length());
if (strstr(userauthlist, "password") == NULL)
{
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 服务器不支持输入password方式验证!" << std::endl;
strLastError = ostr.str();
goto shutdown;
} /* We could authenticate via password */
if (libssh2_userauth_password(session, username.c_str(), password.c_str())) { std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 密码错误!" << std::endl;
strLastError = ostr.str();
goto shutdown;
} sftp_session = libssh2_sftp_init(session);
if (!sftp_session) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 初始化FTL对话失败!" << std::endl;
strLastError = ostr.str();
goto shutdown;
} /* Request a file via SFTP */
sftp_handle =
libssh2_sftp_open(sftp_session, sftppath.c_str(), LIBSSH2_FXF_READ, ); if (!sftp_handle) {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 打开文件失败! " << libssh2_sftp_last_error(sftp_session) << std::endl;
strLastError = ostr.str(); goto shutdown;
} FILE *stream;
if (fopen_s(&stream, localpath.c_str(), "wb") == )
{
do {
char mem[]; /* loop until we fail */
rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem)); if (rc > ) {
//从内存到磁盘
fwrite(mem, , rc, stream);
}
else {
break;
}
} while (); fclose(stream);
}
else {
std::ostringstream ostr;
ostr << "[" << __FILE__ << "][" << __LINE__ << "] 新建本地文件失败 " << localpath << std::endl;
strLastError = ostr.str();
} libssh2_sftp_close(sftp_handle); libssh2_sftp_shutdown(sftp_session); shutdown: libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
libssh2_session_free(session); closesocket(sock);//INVALID_SOCKET return ;
}
}
}

根据上述环境编译成功的libssh2.lib,csdn下载地址:https://download.csdn.net/download/zkfopen/10606098

SFTP客户端代码示例的更多相关文章

  1. socket模块实现基于UDP聊天模拟程序;socketserver模块实现服务端 socket客户端代码示例

    socket模块 serSocket.setblocking(False) 设置为非阻塞: #coding=utf-8 from socket import * import time # 用来存储所 ...

  2. TCP服务器/客户端代码示例

    TCP服务器代码: #include <errno.h> #include <string.h> #include <stdlib.h> #include < ...

  3. UDP服务器/客户端代码示例

    UDP服务器代码: #include <errno.h> #include <string.h> #include <stdlib.h> #include < ...

  4. Dynamics 365客户端编程示例:获取当前用户的信息,表单级通知/提示,表单OnLoad事件执行代码

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  5. 在C#开发中如何使用Client Object Model客户端代码获得SharePoint 网站、列表的权限情况

    自从人类学会了使用火,烤制的方式替代了人类的消化系统部分功能,从此人类的消化系统更加简单,加速了人脑的进化:自从SharePoint 2010开始有了Client Side Object Model ...

  6. 转:HIBERNATE一些_方法_@注解_代码示例---写的非常好

    HIBERNATE一些_方法_@注解_代码示例操作数据库7步骤 : 1 创建一个SessionFactory对象 2 创建Session对象 3 开启事务Transaction : hibernate ...

  7. Java基础知识强化之IO流笔记72:NIO之 NIO核心组件(NIO使用代码示例)

    1.Java NIO 由以下几个核心部分组成: Channels(通道) Buffers(缓冲区) Selectors(选择器) 虽然Java NIO 中除此之外还有很多类和组件,Channel,Bu ...

  8. EzHttp 流传输调用代码示例

    EzHttp框架提供的内置接口,用于文件流等传输 流传输调用代码示例 内置接口: public interface IEzStreamHandler { Task<byte[]> GetD ...

  9. JAVA NIO工作原理及代码示例

    简介:本文主要介绍了JAVA NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例. 欢迎探讨,如有错误敬请 ...

随机推荐

  1. 一个很适合初学者的selenium教程

    http://www.cnblogs.com/hustar0102/p/5885115.html

  2. noi.openjudge 1.13.15

    http://noi.openjudge.cn/ch0113/15/ 总时间限制:  1000ms 内存限制:  65536kB 描述 输入一个长度为N的整数序列 (不多于128个整数),每个整数的范 ...

  3. (点到线段的最短距离)51nod1298 圆与三角形

    1298 圆与三角形 给出圆的圆心和半径,以及三角形的三个顶点,问圆同三角形是否相交.相交输出"Yes",否则输出"No".(三角形的面积大于0).   收起 ...

  4. vue实现购物车和地址选配(二)

    参考文献: vue官网: vue.js 效果展示:全选和取消全选,计算总金额 项目源代码:https://github.com/4561231/hello_world 项目核心代码实现及踩坑 1.全选 ...

  5. eclipse设置

    一.更改文件默认编码 一般每个项目及其项目中的文件的编码都要保持一致,主要是为了不让保存的内容出现乱码:一般会设置UTF-8这个编码格式 设置文件默认编码: windows-->General- ...

  6. 在linux下面解压用的zxpf是什么意思,它跟zxvf有啥区别

    在linux下面解压用的zxpf是什么意思,它跟zxvf有啥区别 linux 命令中tar后跟的zxvf是什么意思:.tar.gz是一个压缩包   .tar只是打包而没有压缩 z:表示 tar 包是被 ...

  7. 反汇编Dis解析

    目录 反汇编dis解析 COMM段BSS段 注释段 Bl指令 title: 反汇编Dis解析 tags: ARM date: 2018-10-21 18:02:58 --- 反汇编dis解析 关于段, ...

  8. springboot单元测试 注入失败 空指针

    今天写代码,在test的类中@Autowired注入要测试的@Component类,但发现一运行就会报空指针异常java.lang.NullPointException,但发现使用new的方法的时候可 ...

  9. Java8新特性 重复注解与类型注解

    import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.anno ...

  10. telnet客户端程序

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types. ...