Socket网络编程--FTP客户端(2)(Windows)
上一篇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)的更多相关文章
- Socket网络编程--FTP客户端(1)(Windows)
已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...
- Socket网络编程--FTP客户端
Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...
- Socket网络编程--FTP客户端(60篇socket博客,而且都比较简单、深入浅出)
已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...
- 基于Socket网络编程
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a2011480169/article/details/73602708 博客核心内容: 1.Sock ...
- windows下的socket网络编程
windows下的socket网络编程 windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了, ...
- windows下的socket网络编程(入门级)
windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先 ...
- 循序渐进Socket网络编程(多客户端、信息共享、文件传输)
循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...
- windows socket 网络编程
样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...
- Python Socket 网络编程 (客户端的编程)
Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...
随机推荐
- mybatis generator(MyBatis的逆向工程)
1创建数据表 如图所示:我的是在text数据库中创建了一个Student表,字段有id(int), name(varchar), age(int), score(int) 2创建项目 ...
- Spring Cloud Zuul性能调整
Spring Cloud 版本: Dalston.SR5 这两天通过JMeter测了一下Spring Cloud Zuul的性能,用的是两台虚机8核8G和4核8G,宿主机是10核逻辑20核,代理的服务 ...
- WinForm中 事件 委托 多线程的应用【以一个下载进度条为例】
第一步:首先我们创建一个winfor的项目 第二步:我们建一个窗体 在一个窗体里面 打开一个另外的窗体 另外的窗体有一个按钮 点击后就开始下载 下载完成后 在注册窗体上面 显示下载完成(达到在一个窗体 ...
- git的几个操作
git reference https://git-scm.com/docs 克隆 从远程仓库克隆一个项目到本地文件夹,命令如下:$ git clone https://github.com/libg ...
- HDUOJ-----Robot Motion
Robot Motion Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- 理解metrics.classification_report
混淆矩阵是一个矩阵,类别个数可以有多个,a[i][j]表示将类别i的样本误判为类别j的个数. classification_report用来分析不同类别的准确率,召回率,F1值等,从而便于按照类别查看 ...
- JavaScript escape() unescape() decodeURI()函数对字符串进行编码解码
定义和用法 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法 escape(string) 参数 描述 string 必需.要被转义或编码的字符串. 返回值 已 ...
- linux sshd ssh 服务的启动和使用
这里使用sshd服务登录到linux系统的方法,不少同学走了弯路,包括我,我一直使用vmware虚拟linux学习使用的,后来windows病毒的原因转入到linux系统中使用 1,sshd服务安装 ...
- 【MySQL】MySQL存储过程介绍
目录结构: contents structure [-] 存储过程简介 关于MySQL的存储过程 MySQL存储过程的创建 格式 声明分割符 参数 变量 注释 MySQL存储过程的调用 MySQL存储 ...
- 【转】Tesla Autopilot
Tesla Autopilot 以下内容是<Tesla Model S的设计失误>一文中新加入的小节.由于写作时间相距太远,而且由于它的时效性,现在也把它单独提出来,独立成文. 两个月前, ...