上一篇FTP客户端讲到如果制作一个简单的FTP客户端,功能实现了,但是后面我们发现了问题,就是FTP是使用明文进行操作的。对于普通情况来说就无所谓了。但有时候要安全的一点的话,就应该使用FTP的安全版本。有SFTP和FTPs,两者都是FTP的安全版本,但是两者的实现原理差别还是很大的,具体自己搜索了解。

0.环境安装

  环境使用我的这一篇文章安装好libssh2库。

  http://www.cnblogs.com/wunaozai/p/4528394.html

  使用一个带有SFTP功能的FTP服务器。注意有些FTP服务器是不带SFTP功能的。这里我使用这个FreeSSHd作为SFTP服务器。

  http://www.freesshd.com/?ctt=download

  关于freesshd配置说两句,Server status标签 点击确定SSH server is running。SSH标签,确定配置完成。Authentication标签下Password authentication为Allowed,Public key authentication为Disabled,这样做的原因是我接下来要做的程序只支持密码登录,减少不必要的干扰,如果有需要,可以自己设定。Tunneling标签,所有选项选中,如果没有选中,本地如果网络复杂的话,可能会有问题。SFTP标签,选择一个作为FTP的根目录。Users标签,增加一个用户。基本设置就这些了。

  

1.示例讲解

  我们先从libssh2中的示例程序进行讲解,libssh2源代码中的example文件夹中有几个常见的示例程序,我们此次先讲解上传文件和下载文件这两个基础功能。

  下面这个是sftp_write_nonblock.c的源代码,已被折叠。

 /*
* Sample showing how to do SFTP non-blocking write transfers.
*
* The sample code has default values for host name, user name, password
* and path to copy, but you can specify them on the command line like:
*
* "sftp 192.168.0.1 user password sftp_write_nonblock.c /tmp/sftp_write_nonblock.c"
*/ #include "libssh2_config.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_SYS_SELECT_H
# include <sys/select.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 <time.h> static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int rc;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir; timeout.tv_sec = ;
timeout.tv_usec = ; FD_ZERO(&fd); FD_SET(socket_fd, &fd); /* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session); if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd; if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd; rc = select(socket_fd + , readfd, writefd, NULL, &timeout); return rc;
} int main(int argc, char *argv[])
{
unsigned long hostaddr;
int sock, i, auth_pw = ;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
const char *username="username";
const char *password="password";
const char *loclfile="sftp_write_nonblock.c";
const char *sftppath="/tmp/sftp_write_nonblock.c";
int rc;
FILE *local;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle;
char mem[ * ];
size_t nread;
char *ptr;
time_t start;
long total = ;
int duration; #ifdef WIN32
WSADATA wsadata;
int err; err = WSAStartup(MAKEWORD(,), &wsadata);
if (err != ) {
fprintf(stderr, "WSAStartup failed with error: %d\n", err);
return ;
}
#endif if (argc > ) {
hostaddr = inet_addr(argv[]);
} else {
hostaddr = htonl(0x7F000001);
} if (argc > ) {
username = argv[];
}
if (argc > ) {
password = argv[];
}
if (argc > ) {
loclfile = argv[];
}
if (argc > ) {
sftppath = argv[];
} rc = libssh2_init ();
if (rc != ) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
return ;
} local = fopen(loclfile, "rb");
if (!local) {
fprintf(stderr, "Can't open local file %s\n", loclfile);
return -;
} /*
* 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();
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != ) {
fprintf(stderr, "failed to connect!\n");
return -;
} /* Create a session instance */
session = libssh2_session_init();
if (!session)
return -; /* Since we have set non-blocking, tell libssh2 we are non-blocking */
libssh2_session_set_blocking(session, ); /* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
while ((rc = libssh2_session_handshake(session, sock))
== LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
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);
fprintf(stderr, "Fingerprint: ");
for(i = ; i < ; i++) {
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
}
fprintf(stderr, "\n"); if (auth_pw) {
/* We could authenticate via password */
while ((rc = libssh2_userauth_password(session, username, password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
} else {
/* Or by public key */
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
"/home/username/.ssh/id_rsa.pub",
"/home/username/.ssh/id_rsa",
password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "\tAuthentication by public key failed\n");
goto shutdown;
}
} fprintf(stderr, "libssh2_sftp_init()!\n");
do {
sftp_session = libssh2_sftp_init(session); if (!sftp_session &&
(libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown;
}
} while (!sftp_session); fprintf(stderr, "libssh2_sftp_open()!\n");
/* Request a file via SFTP */
do {
sftp_handle =
libssh2_sftp_open(sftp_session, sftppath,
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 &&
(libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
fprintf(stderr, "Unable to open file with SFTP\n");
goto shutdown;
}
} while (!sftp_handle); fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n"); start = time(NULL); do {
nread = fread(mem, , sizeof(mem), local);
if (nread <= ) {
/* end of file */
break;
}
ptr = mem; total += nread; do {
/* write data in a loop until we block */
while ((rc = libssh2_sftp_write(sftp_handle, ptr, nread)) ==
LIBSSH2_ERROR_EAGAIN) {
waitsocket(sock, session);
}
if(rc < )
break;
ptr += rc;
nread -= rc; } while (nread);
} while (rc > ); duration = (int)(time(NULL)-start); fprintf(stderr, "%ld bytes in %d seconds makes %.1f bytes/sec\n",
total, duration, total/(double)duration); fclose(local);
libssh2_sftp_close(sftp_handle);
libssh2_sftp_shutdown(sftp_session); shutdown: while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing")
== LIBSSH2_ERROR_EAGAIN);
libssh2_session_free(session); #ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
fprintf(stderr, "all done\n"); libssh2_exit(); return ;
}

  下面这个是sftp_nonblock.c的源代码

 /*
* Sample showing how to do SFTP non-blocking transfers.
*
* The sample code has default values for host name, user name, password
* and path to copy, but you can specify them on the command line like:
*
* "sftp_nonblock 192.168.0.1 user password /tmp/secrets"
*/ #include "libssh2_config.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_SYS_SELECT_H
# include <sys/select.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> /* diff in ms */
static long tvdiff(struct timeval newer, struct timeval older)
{
return (newer.tv_sec-older.tv_sec)*+
(newer.tv_usec-older.tv_usec)/;
} static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int rc;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir; timeout.tv_sec = ;
timeout.tv_usec = ; FD_ZERO(&fd); FD_SET(socket_fd, &fd); /* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session); if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd; if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd; rc = select(socket_fd + , readfd, writefd, NULL, &timeout); return rc;
} int main(int argc, char *argv[])
{
unsigned long hostaddr;
int sock, i, auth_pw = ;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
const char *username="username";
const char *password="password";
const char *sftppath="/tmp/TEST";
struct timeval start;
struct timeval end;
int rc;
int total = ;
long time_ms;
int spin = ;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle; #ifdef WIN32
WSADATA wsadata;
int err; err = WSAStartup(MAKEWORD(,), &wsadata);
if (err != ) {
fprintf(stderr, "WSAStartup failed with error: %d\n", err);
return ;
}
#endif if (argc > ) {
hostaddr = inet_addr(argv[]);
} else {
hostaddr = htonl(0x7F000001);
} if (argc > ) {
username = argv[];
}
if (argc > ) {
password = argv[];
}
if (argc > ) {
sftppath = argv[];
} rc = libssh2_init ();
if (rc != ) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
return ;
} /*
* 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();
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != ) {
fprintf(stderr, "failed to connect!\n");
return -;
} /* Create a session instance */
session = libssh2_session_init();
if (!session)
return -; /* Since we have set non-blocking, tell libssh2 we are non-blocking */
libssh2_session_set_blocking(session, ); gettimeofday(&start, NULL); /* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
while ((rc = libssh2_session_handshake(session, sock)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
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);
fprintf(stderr, "Fingerprint: ");
for(i = ; i < ; i++) {
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
}
fprintf(stderr, "\n"); if (auth_pw) {
/* We could authenticate via password */
while ((rc = libssh2_userauth_password(session, username, password))
== LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
} else {
/* Or by public key */
while ((rc =
libssh2_userauth_publickey_fromfile(session, username,
"/home/username/"
".ssh/id_rsa.pub",
"/home/username/"
".ssh/id_rsa",
password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "\tAuthentication by public key failed\n");
goto shutdown;
}
}
#if 0
libssh2_trace(session, LIBSSH2_TRACE_CONN);
#endif
fprintf(stderr, "libssh2_sftp_init()!\n");
do {
sftp_session = libssh2_sftp_init(session); if(!sftp_session) {
if(libssh2_session_last_errno(session) ==
LIBSSH2_ERROR_EAGAIN) {
fprintf(stderr, "non-blocking init\n");
waitsocket(sock, session); /* now we wait */
}
else {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown;
}
}
} while (!sftp_session); fprintf(stderr, "libssh2_sftp_open()!\n");
/* Request a file via SFTP */
do {
sftp_handle = libssh2_sftp_open(sftp_session, sftppath,
LIBSSH2_FXF_READ, ); if (!sftp_handle) {
if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
fprintf(stderr, "Unable to open file with SFTP\n");
goto shutdown;
}
else {
fprintf(stderr, "non-blocking open\n");
waitsocket(sock, session); /* now we wait */
}
}
} while (!sftp_handle); fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
do {
char mem[*]; /* loop until we fail */
while ((rc = libssh2_sftp_read(sftp_handle, mem,
sizeof(mem))) == LIBSSH2_ERROR_EAGAIN) {
spin++;
waitsocket(sock, session); /* now we wait */
}
if (rc > ) {
total += rc;
write(, mem, rc);
} else {
break;
}
} while (); gettimeofday(&end, NULL);
time_ms = tvdiff(end, start);
fprintf(stderr, "Got %d bytes in %ld ms = %.1f bytes/sec spin: %d\n", total,
time_ms, total/(time_ms/1000.0), spin ); libssh2_sftp_close(sftp_handle);
libssh2_sftp_shutdown(sftp_session); shutdown: fprintf(stderr, "libssh2_session_disconnect\n");
while (libssh2_session_disconnect(session,
"Normal Shutdown, Thank you") ==
LIBSSH2_ERROR_EAGAIN);
libssh2_session_free(session); #ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
fprintf(stderr, "all done\n"); libssh2_exit(); return ;
}

  上面一个是发送文件到sftp服务器,下面是从sftp服务器获取文件。编译和运行结果如下图所示。

  

2.修改示例程序

  软件提供的源代码是比较完整的,为了方便,对里面的功能进行修改。修改为符合本次使用的windows版本,仅支持密码访问。

  sftp-write.c 用于把本地文件上传到sftp服务器中

 #include "libssh2_config.h"
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <winsock2.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h> #define PORT 22
#define HOST "127.0.0.1"
#define USER "user"
#define PWD "user"
#define FILENAME "wunaozai.txt"
#define LOCLFILE "wunaozai.txt" long tvdiff(struct timeval newer, struct timeval older);
int waitsocket(int socket_fd, LIBSSH2_SESSION *session); int main(int argc,char *argv[])
{
int sock, i;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle;
int rc;
FILE *local;
char mem[ * ];
size_t nread;
char *ptr;
time_t start;
long total = ;
int duration;
int ret=-; //用于表示返回结果
int err; WSADATA wsadata;
err = WSAStartup(MAKEWORD(,), &wsadata);
if (err != ) {
fprintf(stderr, "WSAStartup failed with error: %d\n", err);
return ;
} rc = libssh2_init ();
if (rc != ) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
return ;
} local = fopen(LOCLFILE, "rb");
if (!local) {
fprintf(stderr, "Can't open local file %s\n", LOCLFILE);
return -;
} /*
* 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_un.S_addr = inet_addr(HOST);
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != ) {
fprintf(stderr, "failed to connect!\n");
return -;
} /* Create a session instance */
session = libssh2_session_init();
if (!session) return -; /* Since we have set non-blocking, tell libssh2 we are non-blocking */
libssh2_session_set_blocking(session, ); /* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
while ((rc = libssh2_session_handshake(session, sock)) == LIBSSH2_ERROR_EAGAIN)
;
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -;
} //到这里我们还没有权限访问,所以接下来要做的是检查hostkey's finger,然后知道我们验证方式
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
fprintf(stderr, "Fingerprint: ");
for(i = ; i < ; i++) {
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
}
fprintf(stderr, "\n"); //只能使用密码验证
while ((rc = libssh2_userauth_password(session, USER, PWD)) == LIBSSH2_ERROR_EAGAIN)
;
if (rc) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
} //fprintf(stderr, "libssh2_sftp_init()!\n");
do {
sftp_session = libssh2_sftp_init(session);
if (!sftp_session && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown;
}
} while (!sftp_session);
//fprintf(stderr, "libssh2_sftp_open()!\n"); //请求一个文件,通过ssh2方式
do {
sftp_handle =
libssh2_sftp_open(sftp_session, FILENAME, 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 && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
fprintf(stderr, "Unable to open file with SFTP\n"); //可能是没有写入权限,或者没有对应的目录
goto shutdown;
}
} while (!sftp_handle); fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n"); start = time(NULL); do {
nread = fread(mem, , sizeof(mem), local);
if (nread <= ) { //文件结束
break;
}
ptr = mem;
total += nread;
do {
//持续写入文件
while ((rc = libssh2_sftp_write(sftp_handle, ptr, nread)) == LIBSSH2_ERROR_EAGAIN) {
waitsocket(sock, session);
}
if(rc < )
break;
ptr += rc;
nread -= rc;
} while (nread);
} while (rc > ); duration = (int)(time(NULL)-start); fprintf(stderr, "%ldK bytes in %d seconds makes %.1fK bytes/sec\n", total/, duration+, total/((double)duration+)/); fclose(local);
libssh2_sftp_close(sftp_handle);
libssh2_sftp_shutdown(sftp_session); ret = ; //如果执行到这一步,那么表示成功上传文件到服务器
shutdown: while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing") == LIBSSH2_ERROR_EAGAIN)
;
libssh2_session_free(session);
closesocket(sock);
fprintf(stderr, "all done\n");
libssh2_exit(); return ret;
} int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int rc;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir; timeout.tv_sec = ;
timeout.tv_usec = ; FD_ZERO(&fd); FD_SET(socket_fd, &fd); /* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session); if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd; if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd; rc = select(socket_fd + , readfd, writefd, NULL, &timeout);
return rc;
}
/* diff in ms */
long tvdiff(struct timeval newer, struct timeval older)
{
return (newer.tv_sec-older.tv_sec)*+ (newer.tv_usec-older.tv_usec)/;
}

  sftp-read.c 用于把服务器上的文件下载到本地中

 #include "libssh2_config.h"
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <winsock2.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h> #define PORT 22
#define HOST "127.0.0.1"
#define USER "user"
#define PWD "user"
#define FILENAME "wunaozai.txt"
#define LOCLFILE "wunaozai.txt" long tvdiff(struct timeval newer, struct timeval older);
int waitsocket(int socket_fd, LIBSSH2_SESSION *session); int main(int argc, char *argv[])
{
int sock, i;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle;
struct timeval start;
struct timeval end;
int total = ;
long time_ms;
int spin = ;
int ret=;
int rc=;
FILE * fp; WSADATA wsadata;
ret = WSAStartup(MAKEWORD(,), &wsadata);
if (ret != ) {
fprintf(stderr, "WSAStartup failed with error: %d\n", ret);
return ;
} ret = libssh2_init ();
if (ret != ) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", ret);
return ;
} sock = socket(AF_INET, SOCK_STREAM, );
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT); //SFTP默认端口为22端口
sin.sin_addr.S_un.S_addr = inet_addr(HOST);
if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != ) {
fprintf(stderr, "failed to connect!\n");
return -;
} session = libssh2_session_init(); //创建一个session
if (!session) return -; libssh2_session_set_blocking(session, ); //设置为非阻塞方式 while ((ret = libssh2_session_handshake(session, sock)) == LIBSSH2_ERROR_EAGAIN) //创建一个SSH session
; if (ret) {
fprintf(stderr, "Failure establishing SSH session: %d\n", ret);
return -;
}
//到这里我们还没有权限访问,所以接下来要做的是检查hostkey's finger
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
fprintf(stderr, "Fingerprint: ");
for(i = ; i < ; i++) {
fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
}
fprintf(stderr, "\n"); //只是用密码进行验证
while ((ret = libssh2_userauth_password(session, USER, PWD)) == LIBSSH2_ERROR_EAGAIN)
;
if (ret) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown2;
} fprintf(stderr, "libssh2_sftp_init()!\n");
do {
sftp_session = libssh2_sftp_init(session);
if(!sftp_session) {
if(libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
fprintf(stderr, "non-blocking init\n");
waitsocket(sock, session); /* now we wait */
}
else {
fprintf(stderr, "Unable to init SFTP session\n");
goto shutdown2;
}
}
} while (!sftp_session); fprintf(stderr, "libssh2_sftp_open()!\n"); //请求一个文件,通过ssh方式
do {
sftp_handle = libssh2_sftp_open(sftp_session, FILENAME, LIBSSH2_FXF_READ, ); if (!sftp_handle) {
if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
fprintf(stderr, "Unable to open file with SFTP\n");
goto shutdown2;
}
else {
fprintf(stderr, "non-blocking open\n");
waitsocket(sock, session); /* now we wait */
}
}
} while (!sftp_handle); gettimeofday(&start,NULL);
//打开文件进行保存
fp = fopen(LOCLFILE,"wb");
if(fp==NULL)
{
fprintf(stderr,"Can't open local file %s\n",LOCLFILE);
return -;
}
fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
do {
char mem[*]; /* loop until we fail */
while ((ret = libssh2_sftp_read(sftp_handle, mem, sizeof(mem))) == LIBSSH2_ERROR_EAGAIN) {
spin++;
waitsocket(sock, session); /* now we wait */
}
if (ret > ) {
total += ret;
//write(1, mem, ret);
fwrite(mem,,ret,fp); //写入到文件中
} else {
break;
}
} while ();
fclose(fp);
gettimeofday(&end,NULL);
time_ms = tvdiff(end, start);
//打印传输速率
fprintf(stderr, "Got %.4lf Mbytes in %.2lf sec = %.4lf Kbytes/sec spin: %d\n", total/1024.0/1024.0,
time_ms/1000.0, total/((time_ms+)/1000.0)//, spin ); libssh2_sftp_close(sftp_handle);
libssh2_sftp_shutdown(sftp_session); rc = ;//执行到改行代码表示已经正常下载文件 shutdown2: fprintf(stderr, "libssh2_session_disconnect\n");
while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you") == LIBSSH2_ERROR_EAGAIN)
;
libssh2_session_free(session);
closesocket(sock);
fprintf(stderr, "all done\n");
libssh2_exit(); return rc;
} long tvdiff(struct timeval newer, struct timeval older)
{
return (newer.tv_sec-older.tv_sec)*+(newer.tv_usec-older.tv_usec)/;
} int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int ret;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir;
timeout.tv_sec = ;
timeout.tv_usec = ;
FD_ZERO(&fd);
FD_SET(socket_fd, &fd);
/* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session);
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd;
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd;
ret = select(socket_fd + , readfd, writefd, NULL, &timeout);
return ret;
}

  至于用到的libssh2_config.h这个文件,没有的话可以在代码中注释掉.

  

  下面这个是freesshd产生的日志中一部分

 -- :: HOST localhost SSH connection attempt.
-- :: HOST localhost SSH user successfully logged on using password.
-- :: SFTP service granted to user user.
-- :: HOST localhost user is uploading wunaozai.txt (E:\wunaozai.txt)
-- :: HOST localhost SSH user disconnected.
-- :: HOST localhost SSH connection attempt.
-- :: HOST localhost SSH user successfully logged on using password.
-- :: SFTP service granted to user user.
-- :: HOST localhost user is uploading wunaozai.txt (E:\wunaozai.txt)
-- :: HOST localhost SSH user disconnected.
-- :: HOST localhost SSH connection attempt.
-- :: HOST localhost SSH user successfully logged on using password.
-- :: SFTP service granted to user user.
-- :: HOST localhost user is uploading wunaozai.txt (E:\wunaozai.txt)
-- :: HOST localhost SSH user disconnected.
-- :: HOST localhost SSH connection attempt.
-- :: HOST localhost SSH user successfully logged on using password.
-- :: SFTP service granted to user user.
-- :: HOST localhost user is downloading wunaozai.txt (E:\wunaozai.txt)
-- :: HOST localhost SSH user disconnected.

  有了上面这两个主要的功能,SFTP的客户端就基本功能实现了,至于mkdir和dir功能就参考里面的示例程序,基本都可以看懂。

3.使用putty连接freesshd

  了解过SFTP原理之后,就知道,SFTP其实跟FTP没有多大的关系,其实就是一个使用SSH协议,然后进行会话,会话过程保存为文件,嗯,大概就是这个样子了。所以我们可以使用普通的ssh软件进行登录,拿到该SFTP服务器站点的SHELL。然后可以各种操作,看起来很危险的样子,所以不管用什么SFTP服务器在配置用户的时候要注意的。 putty工具里面还有个PSFTP.exe这个工具可以连接到SFTP服务器,没事的也可以玩玩看。

  

  本文地址: http://www.cnblogs.com/wunaozai/p/4534302.html

Socket网络编程--FTP客户端(2)(Windows)的更多相关文章

  1. Socket网络编程--FTP客户端(1)(Windows)

    已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...

  2. Socket网络编程--FTP客户端

    Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...

  3. Socket网络编程--FTP客户端(60篇socket博客,而且都比较简单、深入浅出)

    已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...

  4. 基于Socket网络编程

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a2011480169/article/details/73602708 博客核心内容: 1.Sock ...

  5. windows下的socket网络编程

    windows下的socket网络编程 windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了, ...

  6. windows下的socket网络编程(入门级)

    windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先 ...

  7. 循序渐进Socket网络编程(多客户端、信息共享、文件传输)

    循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...

  8. windows socket 网络编程

    样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...

  9. Python Socket 网络编程 (客户端的编程)

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

随机推荐

  1. Excel分数、小数、身份证的录入

    身份证输入: 方法1:将单元格格式设置为文本,在输入数据 方法2:在输入之前输入英文状态下的单引号在输入数据 分数输入: 办法1:0[空格]数字/数字,如:0 1/3 办法2:将需要输入数据的区域设置 ...

  2. urllib2特点--urllib2.build_opener对象接口

    # -*- coding: cp936 -*- #python 27 #xiaodeng #urllib2特点--urllib2.build_opener对象接口 import urllib2 imp ...

  3. code vs 2597 团伙

    题目描述 Description 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友 ...

  4. error:No buffer space available (maximum connections reached

    2015-02-02 17:49:09,035 ERROR basic.DBManager - Failded to establish the connection. com.mysql.jdbc. ...

  5. tomcat,很多时候,可以在服务server.xml中可以实现一些效果

    一.--日志 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="log ...

  6. Silverlight for Windows Phone开发系列课程

    Silverlight for Windows Phone开发系列课程(1):Windows Phone平台概况         课程简介:本节开始介绍系列课程的概况,包括课程内容,先决条件,学习目的 ...

  7. git log退出方法

    英文状态下按Q

  8. 企业内知识库wiki所存在的问题

    相信很多公司都利用开源的wiki web app搭建了自家的内部wiki服务,比如使用media Wiki, Gollum, doku wiki, jsWiki等 但是,真正可用的企业wiki系统却没 ...

  9. Facade 设计模式

    目的 在一个子系统的一组接口上提供一个统一的接口.Facade 设计模式定义了一个更高级别的接口,使子系统更容易使用. 通过一个更加简洁的接口来包装一个复杂的子系统. 解决的问题 客户端需要一个简化的 ...

  10. mysql中Table is read only错误解决方法

    今天再我把数据库data 拷贝到linux 下运行程序 ”mysql中Table is read only的解决“ 出现这样的问题,查询资料. linux下执行如下命令即可 #mysqladmin - ...