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

时间:2022-04-17 01:19:49

  上一篇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标签,增加一个用户。基本设置就这些了。

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

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服务器获取文件。编译和运行结果如下图所示。

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

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这个文件,没有的话可以在代码中注释掉.

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

  下面这个是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服务器,没事的也可以玩玩看。

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

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