• 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的源代码,已被折叠。

      1 /*
      2  * Sample showing how to do SFTP non-blocking write transfers.
      3  *
      4  * The sample code has default values for host name, user name, password
      5  * and path to copy, but you can specify them on the command line like:
      6  *
      7  * "sftp 192.168.0.1 user password sftp_write_nonblock.c /tmp/sftp_write_nonblock.c"
      8  */
      9 
     10 #include "libssh2_config.h"
     11 #include <libssh2.h>
     12 #include <libssh2_sftp.h>
     13 
     14 #ifdef HAVE_WINSOCK2_H
     15 # include <winsock2.h>
     16 #endif
     17 #ifdef HAVE_SYS_SOCKET_H
     18 # include <sys/socket.h>
     19 #endif
     20 #ifdef HAVE_NETINET_IN_H
     21 # include <netinet/in.h>
     22 #endif
     23 #ifdef HAVE_SYS_SELECT_H
     24 # include <sys/select.h>
     25 #endif
     26 # ifdef HAVE_UNISTD_H
     27 #include <unistd.h>
     28 #endif
     29 #ifdef HAVE_ARPA_INET_H
     30 # include <arpa/inet.h>
     31 #endif
     32 #ifdef HAVE_SYS_TIME_H
     33 # include <sys/time.h>
     34 #endif
     35 
     36 #include <sys/types.h>
     37 #include <fcntl.h>
     38 #include <errno.h>
     39 #include <stdio.h>
     40 #include <ctype.h>
     41 #include <time.h>
     42 
     43 static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
     44 {
     45     struct timeval timeout;
     46     int rc;
     47     fd_set fd;
     48     fd_set *writefd = NULL;
     49     fd_set *readfd = NULL;
     50     int dir;
     51 
     52     timeout.tv_sec = 10;
     53     timeout.tv_usec = 0;
     54 
     55     FD_ZERO(&fd);
     56 
     57     FD_SET(socket_fd, &fd);
     58 
     59     /* now make sure we wait in the correct direction */
     60     dir = libssh2_session_block_directions(session);
     61 
     62     if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
     63         readfd = &fd;
     64 
     65     if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
     66         writefd = &fd;
     67 
     68     rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
     69 
     70     return rc;
     71 }
     72 
     73 int main(int argc, char *argv[])
     74 {
     75     unsigned long hostaddr;
     76     int sock, i, auth_pw = 1;
     77     struct sockaddr_in sin;
     78     const char *fingerprint;
     79     LIBSSH2_SESSION *session;
     80     const char *username="username";
     81     const char *password="password";
     82     const char *loclfile="sftp_write_nonblock.c";
     83     const char *sftppath="/tmp/sftp_write_nonblock.c";
     84     int rc;
     85     FILE *local;
     86     LIBSSH2_SFTP *sftp_session;
     87     LIBSSH2_SFTP_HANDLE *sftp_handle;
     88     char mem[1024 * 100];
     89     size_t nread;
     90     char *ptr;
     91     time_t start;
     92     long total = 0;
     93     int duration;
     94 
     95 #ifdef WIN32
     96     WSADATA wsadata;
     97     int err;
     98 
     99     err = WSAStartup(MAKEWORD(2,0), &wsadata);
    100     if (err != 0) {
    101         fprintf(stderr, "WSAStartup failed with error: %d
    ", err);
    102         return 1;
    103     }
    104 #endif
    105 
    106     if (argc > 1) {
    107         hostaddr = inet_addr(argv[1]);
    108     } else {
    109         hostaddr = htonl(0x7F000001);
    110     }
    111 
    112     if (argc > 2) {
    113         username = argv[2];
    114     }
    115     if (argc > 3) {
    116         password = argv[3];
    117     }
    118     if (argc > 4) {
    119         loclfile = argv[4];
    120     }
    121     if (argc > 5) {
    122         sftppath = argv[5];
    123     }
    124 
    125     rc = libssh2_init (0);
    126     if (rc != 0) {
    127         fprintf (stderr, "libssh2 initialization failed (%d)
    ", rc);
    128         return 1;
    129     }
    130 
    131     local = fopen(loclfile, "rb");
    132     if (!local) {
    133         fprintf(stderr, "Can't open local file %s
    ", loclfile);
    134         return -1;
    135     }
    136 
    137     /*
    138      * The application code is responsible for creating the socket
    139      * and establishing the connection
    140      */
    141     sock = socket(AF_INET, SOCK_STREAM, 0);
    142 
    143     sin.sin_family = AF_INET;
    144     sin.sin_port = htons(22);
    145     sin.sin_addr.s_addr = hostaddr;
    146     if (connect(sock, (struct sockaddr*)(&sin),
    147                 sizeof(struct sockaddr_in)) != 0) {
    148         fprintf(stderr, "failed to connect!
    ");
    149         return -1;
    150     }
    151 
    152     /* Create a session instance */
    153     session = libssh2_session_init();
    154     if (!session)
    155         return -1;
    156 
    157     /* Since we have set non-blocking, tell libssh2 we are non-blocking */
    158     libssh2_session_set_blocking(session, 0);
    159 
    160     /* ... start it up. This will trade welcome banners, exchange keys,
    161         * and setup crypto, compression, and MAC layers
    162         */
    163     while ((rc = libssh2_session_handshake(session, sock))
    164            == LIBSSH2_ERROR_EAGAIN);
    165     if (rc) {
    166         fprintf(stderr, "Failure establishing SSH session: %d
    ", rc);
    167         return -1;
    168     }
    169 
    170     /* At this point we havn't yet authenticated.  The first thing to do is
    171      * check the hostkey's fingerprint against our known hosts Your app may
    172      * have it hard coded, may go to a file, may present it to the user,
    173      * that's your call
    174      */
    175     fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
    176     fprintf(stderr, "Fingerprint: ");
    177     for(i = 0; i < 20; i++) {
    178         fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
    179     }
    180     fprintf(stderr, "
    ");
    181 
    182     if (auth_pw) {
    183         /* We could authenticate via password */
    184         while ((rc = libssh2_userauth_password(session, username, password)) ==
    185                LIBSSH2_ERROR_EAGAIN);
    186         if (rc) {
    187             fprintf(stderr, "Authentication by password failed.
    ");
    188             goto shutdown;
    189         }
    190     } else {
    191         /* Or by public key */
    192         while ((rc = libssh2_userauth_publickey_fromfile(session, username,
    193                                                          "/home/username/.ssh/id_rsa.pub",
    194                                                          "/home/username/.ssh/id_rsa",
    195                                                          password)) ==
    196                LIBSSH2_ERROR_EAGAIN);
    197     if (rc) {
    198             fprintf(stderr, "	Authentication by public key failed
    ");
    199             goto shutdown;
    200         }
    201     }
    202 
    203     fprintf(stderr, "libssh2_sftp_init()!
    ");
    204     do {
    205         sftp_session = libssh2_sftp_init(session);
    206 
    207         if (!sftp_session &&
    208             (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
    209             fprintf(stderr, "Unable to init SFTP session
    ");
    210             goto shutdown;
    211         }
    212     } while (!sftp_session);
    213 
    214     fprintf(stderr, "libssh2_sftp_open()!
    ");
    215     /* Request a file via SFTP */
    216     do {
    217         sftp_handle =
    218         libssh2_sftp_open(sftp_session, sftppath,
    219                           LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
    220                           LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
    221                           LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
    222 
    223         if (!sftp_handle &&
    224             (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
    225             fprintf(stderr, "Unable to open file with SFTP
    ");
    226             goto shutdown;
    227         }
    228     } while (!sftp_handle);
    229 
    230     fprintf(stderr, "libssh2_sftp_open() is done, now send data!
    ");
    231 
    232     start = time(NULL);
    233 
    234     do {
    235         nread = fread(mem, 1, sizeof(mem), local);
    236         if (nread <= 0) {
    237             /* end of file */
    238             break;
    239         }
    240         ptr = mem;
    241 
    242         total += nread;
    243 
    244         do {
    245             /* write data in a loop until we block */
    246             while ((rc = libssh2_sftp_write(sftp_handle, ptr, nread)) ==
    247                    LIBSSH2_ERROR_EAGAIN) {
    248                 waitsocket(sock, session);
    249             }
    250             if(rc < 0)
    251                 break;
    252             ptr += rc;
    253             nread -= rc;
    254 
    255         } while (nread);
    256     } while (rc > 0);
    257 
    258     duration = (int)(time(NULL)-start);
    259 
    260     fprintf(stderr, "%ld bytes in %d seconds makes %.1f bytes/sec
    ",
    261            total, duration, total/(double)duration);
    262 
    263 
    264     fclose(local);
    265     libssh2_sftp_close(sftp_handle);
    266     libssh2_sftp_shutdown(sftp_session);
    267 
    268 shutdown:
    269 
    270     while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing")
    271            == LIBSSH2_ERROR_EAGAIN);
    272     libssh2_session_free(session);
    273 
    274 #ifdef WIN32
    275     closesocket(sock);
    276 #else
    277     close(sock);
    278 #endif
    279     fprintf(stderr, "all done
    ");
    280 
    281     libssh2_exit();
    282 
    283     return 0;
    284 }
    View Code

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

      1 /*
      2  * Sample showing how to do SFTP non-blocking transfers.
      3  *
      4  * The sample code has default values for host name, user name, password
      5  * and path to copy, but you can specify them on the command line like:
      6  *
      7  * "sftp_nonblock 192.168.0.1 user password /tmp/secrets"
      8  */
      9 
     10 #include "libssh2_config.h"
     11 #include <libssh2.h>
     12 #include <libssh2_sftp.h>
     13 
     14 #ifdef HAVE_WINSOCK2_H
     15 # include <winsock2.h>
     16 #endif
     17 #ifdef HAVE_SYS_SOCKET_H
     18 # include <sys/socket.h>
     19 #endif
     20 #ifdef HAVE_NETINET_IN_H
     21 # include <netinet/in.h>
     22 #endif
     23 #ifdef HAVE_SYS_SELECT_H
     24 # include <sys/select.h>
     25 #endif
     26 # ifdef HAVE_UNISTD_H
     27 #include <unistd.h>
     28 #endif
     29 #ifdef HAVE_ARPA_INET_H
     30 # include <arpa/inet.h>
     31 #endif
     32 #ifdef HAVE_SYS_TIME_H
     33 # include <sys/time.h>
     34 #endif
     35 
     36 #include <sys/types.h>
     37 #include <fcntl.h>
     38 #include <errno.h>
     39 #include <stdio.h>
     40 #include <ctype.h>
     41 
     42 /* diff in ms */
     43 static long tvdiff(struct timeval newer, struct timeval older)
     44 {
     45   return (newer.tv_sec-older.tv_sec)*1000+
     46       (newer.tv_usec-older.tv_usec)/1000;
     47 }
     48 
     49 static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
     50 {
     51     struct timeval timeout;
     52     int rc;
     53     fd_set fd;
     54     fd_set *writefd = NULL;
     55     fd_set *readfd = NULL;
     56     int dir;
     57 
     58     timeout.tv_sec = 10;
     59     timeout.tv_usec = 0;
     60 
     61     FD_ZERO(&fd);
     62 
     63     FD_SET(socket_fd, &fd);
     64 
     65     /* now make sure we wait in the correct direction */
     66     dir = libssh2_session_block_directions(session);
     67 
     68     if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
     69         readfd = &fd;
     70 
     71     if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
     72         writefd = &fd;
     73 
     74     rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
     75 
     76     return rc;
     77 }
     78 
     79 int main(int argc, char *argv[])
     80 {
     81     unsigned long hostaddr;
     82     int sock, i, auth_pw = 1;
     83     struct sockaddr_in sin;
     84     const char *fingerprint;
     85     LIBSSH2_SESSION *session;
     86     const char *username="username";
     87     const char *password="password";
     88     const char *sftppath="/tmp/TEST";
     89     struct timeval start;
     90     struct timeval end;
     91     int rc;
     92     int total = 0;
     93     long time_ms;
     94     int spin = 0;
     95     LIBSSH2_SFTP *sftp_session;
     96     LIBSSH2_SFTP_HANDLE *sftp_handle;
     97 
     98 #ifdef WIN32
     99     WSADATA wsadata;
    100     int err;
    101 
    102     err = WSAStartup(MAKEWORD(2,0), &wsadata);
    103     if (err != 0) {
    104         fprintf(stderr, "WSAStartup failed with error: %d
    ", err);
    105         return 1;
    106     }
    107 #endif
    108 
    109     if (argc > 1) {
    110         hostaddr = inet_addr(argv[1]);
    111     } else {
    112         hostaddr = htonl(0x7F000001);
    113     }
    114 
    115     if (argc > 2) {
    116         username = argv[2];
    117     }
    118     if (argc > 3) {
    119         password = argv[3];
    120     }
    121     if (argc > 4) {
    122         sftppath = argv[4];
    123     }
    124 
    125     rc = libssh2_init (0);
    126     if (rc != 0) {
    127         fprintf (stderr, "libssh2 initialization failed (%d)
    ", rc);
    128         return 1;
    129     }
    130 
    131     /*
    132      * The application code is responsible for creating the socket
    133      * and establishing the connection
    134      */
    135     sock = socket(AF_INET, SOCK_STREAM, 0);
    136 
    137     sin.sin_family = AF_INET;
    138     sin.sin_port = htons(22);
    139     sin.sin_addr.s_addr = hostaddr;
    140     if (connect(sock, (struct sockaddr*)(&sin),
    141                 sizeof(struct sockaddr_in)) != 0) {
    142         fprintf(stderr, "failed to connect!
    ");
    143         return -1;
    144     }
    145 
    146     /* Create a session instance */
    147     session = libssh2_session_init();
    148     if (!session)
    149         return -1;
    150 
    151     /* Since we have set non-blocking, tell libssh2 we are non-blocking */
    152     libssh2_session_set_blocking(session, 0);
    153 
    154     gettimeofday(&start, NULL);
    155 
    156     /* ... start it up. This will trade welcome banners, exchange keys,
    157         * and setup crypto, compression, and MAC layers
    158         */
    159     while ((rc = libssh2_session_handshake(session, sock)) ==
    160            LIBSSH2_ERROR_EAGAIN);
    161     if (rc) {
    162         fprintf(stderr, "Failure establishing SSH session: %d
    ", rc);
    163         return -1;
    164     }
    165 
    166     /* At this point we havn't yet authenticated.  The first thing to do
    167         * is check the hostkey's fingerprint against our known hosts Your app
    168         * may have it hard coded, may go to a file, may present it to the
    169         * user, that's your call
    170         */
    171     fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
    172     fprintf(stderr, "Fingerprint: ");
    173     for(i = 0; i < 20; i++) {
    174         fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
    175     }
    176     fprintf(stderr, "
    ");
    177 
    178     if (auth_pw) {
    179         /* We could authenticate via password */
    180         while ((rc = libssh2_userauth_password(session, username, password))
    181                == LIBSSH2_ERROR_EAGAIN);
    182         if (rc) {
    183             fprintf(stderr, "Authentication by password failed.
    ");
    184             goto shutdown;
    185         }
    186     } else {
    187         /* Or by public key */
    188         while ((rc =
    189                 libssh2_userauth_publickey_fromfile(session, username,
    190                                                     "/home/username/"
    191                                                     ".ssh/id_rsa.pub",
    192                                                     "/home/username/"
    193                                                     ".ssh/id_rsa",
    194                                                     password)) ==
    195                LIBSSH2_ERROR_EAGAIN);
    196         if (rc) {
    197             fprintf(stderr, "	Authentication by public key failed
    ");
    198             goto shutdown;
    199         }
    200     }
    201 #if 0
    202     libssh2_trace(session, LIBSSH2_TRACE_CONN);
    203 #endif
    204     fprintf(stderr, "libssh2_sftp_init()!
    ");
    205     do {
    206         sftp_session = libssh2_sftp_init(session);
    207 
    208         if(!sftp_session) {
    209             if(libssh2_session_last_errno(session) ==
    210                LIBSSH2_ERROR_EAGAIN) {
    211                 fprintf(stderr, "non-blocking init
    ");
    212                 waitsocket(sock, session); /* now we wait */
    213             }
    214             else {
    215                 fprintf(stderr, "Unable to init SFTP session
    ");
    216                 goto shutdown;
    217             }
    218         }
    219     } while (!sftp_session);
    220 
    221     fprintf(stderr, "libssh2_sftp_open()!
    ");
    222     /* Request a file via SFTP */
    223     do {
    224         sftp_handle = libssh2_sftp_open(sftp_session, sftppath,
    225                                         LIBSSH2_FXF_READ, 0);
    226 
    227         if (!sftp_handle) {
    228             if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
    229                 fprintf(stderr, "Unable to open file with SFTP
    ");
    230                 goto shutdown;
    231             }
    232             else {
    233                 fprintf(stderr, "non-blocking open
    ");
    234                 waitsocket(sock, session); /* now we wait */
    235             }
    236         }
    237     } while (!sftp_handle);
    238 
    239     fprintf(stderr, "libssh2_sftp_open() is done, now receive data!
    ");
    240     do {
    241         char mem[1024*24];
    242 
    243         /* loop until we fail */
    244         while ((rc = libssh2_sftp_read(sftp_handle, mem,
    245                                        sizeof(mem))) == LIBSSH2_ERROR_EAGAIN) {
    246             spin++;
    247             waitsocket(sock, session); /* now we wait */
    248         }
    249         if (rc > 0) {
    250             total += rc;
    251             write(1, mem, rc);
    252         } else {
    253             break;
    254         }
    255     } while (1);
    256 
    257     gettimeofday(&end, NULL);
    258     time_ms = tvdiff(end, start);
    259     fprintf(stderr, "Got %d bytes in %ld ms = %.1f bytes/sec spin: %d
    ", total,
    260            time_ms, total/(time_ms/1000.0), spin );
    261 
    262     libssh2_sftp_close(sftp_handle);
    263     libssh2_sftp_shutdown(sftp_session);
    264 
    265 shutdown:
    266 
    267     fprintf(stderr, "libssh2_session_disconnect
    ");
    268     while (libssh2_session_disconnect(session,
    269                                       "Normal Shutdown, Thank you") ==
    270            LIBSSH2_ERROR_EAGAIN);
    271     libssh2_session_free(session);
    272 
    273 #ifdef WIN32
    274     closesocket(sock);
    275 #else
    276     close(sock);
    277 #endif
    278     fprintf(stderr, "all done
    ");
    279 
    280     libssh2_exit();
    281 
    282     return 0;
    283 }
    View Code

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

      

    2.修改示例程序

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

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

      1 #include "libssh2_config.h"
      2 #include <libssh2.h>
      3 #include <libssh2_sftp.h>
      4 #include <winsock2.h>
      5 #include <unistd.h>
      6 #include <sys/time.h>
      7 #include <sys/types.h>
      8 #include <fcntl.h>
      9 #include <errno.h>
     10 #include <stdio.h>
     11 #include <ctype.h>
     12 
     13 #define PORT 22
     14 #define HOST "127.0.0.1"
     15 #define USER "user"
     16 #define PWD  "user"
     17 #define FILENAME "wunaozai.txt"
     18 #define LOCLFILE "wunaozai.txt"
     19 
     20 long tvdiff(struct timeval newer, struct timeval older);
     21 int waitsocket(int socket_fd, LIBSSH2_SESSION *session);
     22 
     23 int main(int argc,char *argv[])
     24 {
     25     int sock, i;
     26     struct sockaddr_in sin;
     27     const char *fingerprint;
     28     LIBSSH2_SESSION *session;
     29     LIBSSH2_SFTP *sftp_session;
     30     LIBSSH2_SFTP_HANDLE *sftp_handle;
     31     int rc;
     32     FILE *local;
     33     char mem[1024 * 100];
     34     size_t nread;
     35     char *ptr;
     36     time_t start;
     37     long total = 0;
     38     int duration;
     39     int ret=-1; //用于表示返回结果
     40     int err;
     41 
     42     WSADATA wsadata;
     43     err = WSAStartup(MAKEWORD(2,0), &wsadata);
     44     if (err != 0) {
     45         fprintf(stderr, "WSAStartup failed with error: %d
    ", err);
     46         return 1;
     47     }
     48 
     49     rc = libssh2_init (0);
     50     if (rc != 0) {
     51         fprintf (stderr, "libssh2 initialization failed (%d)
    ", rc);
     52         return 1;
     53     }
     54 
     55     local = fopen(LOCLFILE, "rb");
     56     if (!local) {
     57         fprintf(stderr, "Can't open local file %s
    ", LOCLFILE);
     58         return -1;
     59     }
     60 
     61     /*
     62      * The application code is responsible for creating the socket
     63      * and establishing the connection
     64      */
     65     sock = socket(AF_INET, SOCK_STREAM, 0);
     66 
     67     sin.sin_family = AF_INET;
     68     sin.sin_port = htons(PORT);
     69     sin.sin_addr.S_un.S_addr = inet_addr(HOST);
     70     if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
     71         fprintf(stderr, "failed to connect!
    ");
     72         return -1;
     73     }
     74 
     75     /* Create a session instance */
     76     session = libssh2_session_init();
     77     if (!session) return -1;
     78 
     79     /* Since we have set non-blocking, tell libssh2 we are non-blocking */
     80     libssh2_session_set_blocking(session, 0);
     81 
     82     /* ... start it up. This will trade welcome banners, exchange keys,
     83      * and setup crypto, compression, and MAC layers
     84      */
     85     while ((rc = libssh2_session_handshake(session, sock)) == LIBSSH2_ERROR_EAGAIN)
     86         ;
     87     if (rc) {
     88         fprintf(stderr, "Failure establishing SSH session: %d
    ", rc);
     89         return -1;
     90     }
     91 
     92     //到这里我们还没有权限访问,所以接下来要做的是检查hostkey's finger,然后知道我们验证方式
     93     fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
     94     fprintf(stderr, "Fingerprint: ");
     95     for(i = 0; i < 20; i++) {
     96         fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
     97     }
     98     fprintf(stderr, "
    ");
     99 
    100     //只能使用密码验证
    101     while ((rc = libssh2_userauth_password(session, USER, PWD)) == LIBSSH2_ERROR_EAGAIN)
    102         ;
    103     if (rc) {
    104         fprintf(stderr, "Authentication by password failed.
    ");
    105         goto shutdown;
    106     }
    107 
    108     //fprintf(stderr, "libssh2_sftp_init()!
    ");
    109     do {
    110         sftp_session = libssh2_sftp_init(session);
    111         if (!sftp_session && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
    112             fprintf(stderr, "Unable to init SFTP session
    ");
    113             goto shutdown;
    114         }
    115     } while (!sftp_session);
    116     //fprintf(stderr, "libssh2_sftp_open()!
    ");
    117 
    118 
    119     //请求一个文件,通过ssh2方式
    120     do {
    121         sftp_handle =
    122             libssh2_sftp_open(sftp_session, FILENAME, LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
    123                     LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
    124                     LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
    125 
    126         if (!sftp_handle && (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN)) {
    127             fprintf(stderr, "Unable to open file with SFTP
    "); //可能是没有写入权限,或者没有对应的目录
    128             goto shutdown;
    129         }
    130     } while (!sftp_handle);
    131 
    132     fprintf(stderr, "libssh2_sftp_open() is done, now send data!
    ");
    133 
    134     start = time(NULL);
    135 
    136     do {
    137         nread = fread(mem, 1, sizeof(mem), local);
    138         if (nread <= 0) { //文件结束
    139             break;
    140         }
    141         ptr = mem;
    142         total += nread;
    143         do {
    144             //持续写入文件
    145             while ((rc = libssh2_sftp_write(sftp_handle, ptr, nread)) == LIBSSH2_ERROR_EAGAIN) {
    146                 waitsocket(sock, session);
    147             }
    148             if(rc < 0)
    149                 break;
    150             ptr += rc;
    151             nread -= rc;
    152         } while (nread);
    153     } while (rc > 0);
    154 
    155     duration = (int)(time(NULL)-start);
    156 
    157     fprintf(stderr, "%ldK bytes in %d seconds makes %.1fK bytes/sec
    ", total/1024, duration+1, total/((double)duration+1)/1024);
    158 
    159 
    160     fclose(local);
    161     libssh2_sftp_close(sftp_handle);
    162     libssh2_sftp_shutdown(sftp_session);
    163 
    164     ret = 0; //如果执行到这一步,那么表示成功上传文件到服务器
    165 shutdown:
    166 
    167     while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing") == LIBSSH2_ERROR_EAGAIN)
    168         ;
    169     libssh2_session_free(session);
    170     closesocket(sock);
    171     fprintf(stderr, "all done
    ");
    172     libssh2_exit();
    173 
    174     return ret;
    175 }
    176 
    177 int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
    178 {
    179     struct timeval timeout;
    180     int rc;
    181     fd_set fd;
    182     fd_set *writefd = NULL;
    183     fd_set *readfd = NULL;
    184     int dir;
    185 
    186     timeout.tv_sec = 10;
    187     timeout.tv_usec = 0;
    188 
    189     FD_ZERO(&fd);
    190 
    191     FD_SET(socket_fd, &fd);
    192 
    193     /* now make sure we wait in the correct direction */
    194     dir = libssh2_session_block_directions(session);
    195 
    196     if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
    197         readfd = &fd;
    198 
    199     if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
    200         writefd = &fd;
    201 
    202     rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
    203     return rc;
    204 }
    205 /* diff in ms */
    206 long tvdiff(struct timeval newer, struct timeval older)
    207 {
    208     return (newer.tv_sec-older.tv_sec)*1000+ (newer.tv_usec-older.tv_usec)/1000;
    209 }
    View Code

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

      1 #include "libssh2_config.h"
      2 #include <libssh2.h>
      3 #include <libssh2_sftp.h>
      4 #include <winsock2.h>
      5 #include <unistd.h>
      6 #include <sys/time.h>
      7 #include <sys/types.h>
      8 #include <fcntl.h>
      9 #include <errno.h>
     10 #include <stdio.h>
     11 #include <ctype.h>
     12 
     13 #define PORT 22
     14 #define HOST "127.0.0.1"
     15 #define USER "user"
     16 #define PWD  "user"
     17 #define FILENAME "wunaozai.txt"
     18 #define LOCLFILE "wunaozai.txt"
     19 
     20 long tvdiff(struct timeval newer, struct timeval older);
     21 int waitsocket(int socket_fd, LIBSSH2_SESSION *session);
     22 
     23 
     24 int main(int argc, char *argv[])
     25 {
     26     int sock, i;
     27     struct sockaddr_in sin;
     28     const char *fingerprint;
     29     LIBSSH2_SESSION *session;
     30     LIBSSH2_SFTP *sftp_session;
     31     LIBSSH2_SFTP_HANDLE *sftp_handle;
     32     struct timeval start;
     33     struct timeval end;
     34     int total = 0;
     35     long time_ms;
     36     int spin = 0;
     37     int ret=0;
     38     int rc=1;
     39     FILE * fp;
     40 
     41     WSADATA wsadata;
     42     ret = WSAStartup(MAKEWORD(2,0), &wsadata);
     43     if (ret != 0) {
     44         fprintf(stderr, "WSAStartup failed with error: %d
    ", ret);
     45         return 1;
     46     }
     47 
     48     ret = libssh2_init (0);
     49     if (ret != 0) {
     50         fprintf (stderr, "libssh2 initialization failed (%d)
    ", ret);
     51         return 1;
     52     }
     53 
     54     sock = socket(AF_INET, SOCK_STREAM, 0);
     55     sin.sin_family = AF_INET;
     56     sin.sin_port = htons(PORT); //SFTP默认端口为22端口
     57     sin.sin_addr.S_un.S_addr = inet_addr(HOST);
     58     if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
     59         fprintf(stderr, "failed to connect!
    ");
     60         return -1;
     61     }
     62 
     63     session = libssh2_session_init(); //创建一个session
     64     if (!session) return -1;
     65 
     66     libssh2_session_set_blocking(session, 0); //设置为非阻塞方式
     67 
     68     while ((ret = libssh2_session_handshake(session, sock)) == LIBSSH2_ERROR_EAGAIN) //创建一个SSH session
     69         ;
     70 
     71     if (ret) {
     72         fprintf(stderr, "Failure establishing SSH session: %d
    ", ret);
     73         return -1;
     74     }
     75     //到这里我们还没有权限访问,所以接下来要做的是检查hostkey's finger
     76     fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
     77     fprintf(stderr, "Fingerprint: ");
     78     for(i = 0; i < 20; i++) {
     79         fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
     80     }
     81     fprintf(stderr, "
    ");
     82 
     83     //只是用密码进行验证
     84     while ((ret = libssh2_userauth_password(session, USER, PWD)) == LIBSSH2_ERROR_EAGAIN)
     85         ;
     86     if (ret) {
     87         fprintf(stderr, "Authentication by password failed.
    ");
     88         goto shutdown2;
     89     }
     90 
     91     fprintf(stderr, "libssh2_sftp_init()!
    ");
     92     do {
     93         sftp_session = libssh2_sftp_init(session);
     94         if(!sftp_session) {
     95             if(libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
     96                 fprintf(stderr, "non-blocking init
    ");
     97                 waitsocket(sock, session); /* now we wait */
     98             }
     99             else {
    100                 fprintf(stderr, "Unable to init SFTP session
    ");
    101                 goto shutdown2;
    102             }
    103         }
    104     } while (!sftp_session);
    105 
    106     fprintf(stderr, "libssh2_sftp_open()!
    ");
    107 
    108     //请求一个文件,通过ssh方式
    109     do {
    110         sftp_handle = libssh2_sftp_open(sftp_session, FILENAME, LIBSSH2_FXF_READ, 0);
    111 
    112         if (!sftp_handle) {
    113             if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
    114                 fprintf(stderr, "Unable to open file with SFTP
    ");
    115                 goto shutdown2;
    116             }
    117             else {
    118                 fprintf(stderr, "non-blocking open
    ");
    119                 waitsocket(sock, session); /* now we wait */
    120             }
    121         }
    122     } while (!sftp_handle);
    123 
    124     gettimeofday(&start,NULL);
    125     //打开文件进行保存
    126     fp = fopen(LOCLFILE,"wb");
    127     if(fp==NULL)
    128     {
    129         fprintf(stderr,"Can't open local file %s
    ",LOCLFILE);
    130         return -1;
    131     }
    132     fprintf(stderr, "libssh2_sftp_open() is done, now receive data!
    ");
    133     do {
    134         char mem[1024*24];
    135 
    136         /* loop until we fail */
    137         while ((ret = libssh2_sftp_read(sftp_handle, mem, sizeof(mem))) == LIBSSH2_ERROR_EAGAIN) {
    138             spin++;
    139             waitsocket(sock, session); /* now we wait */
    140         }
    141         if (ret > 0) {
    142             total += ret;
    143             //write(1, mem, ret);
    144             fwrite(mem,1,ret,fp); //写入到文件中
    145         } else {
    146             break;
    147         }
    148     } while (1);
    149     fclose(fp);
    150     gettimeofday(&end,NULL);
    151     time_ms = tvdiff(end, start);
    152     //打印传输速率
    153     fprintf(stderr, "Got %.4lf Mbytes in %.2lf sec = %.4lf Kbytes/sec spin: %d
    ", total/1024.0/1024.0,
    154             time_ms/1000.0, total/((time_ms+1)/1000.0)/1024/1024, spin );
    155 
    156     libssh2_sftp_close(sftp_handle);
    157     libssh2_sftp_shutdown(sftp_session);
    158 
    159     rc = 0;//执行到改行代码表示已经正常下载文件
    160 
    161 shutdown2:
    162 
    163     fprintf(stderr, "libssh2_session_disconnect
    ");
    164     while (libssh2_session_disconnect(session, "Normal Shutdown, Thank you") == LIBSSH2_ERROR_EAGAIN)
    165         ;
    166     libssh2_session_free(session);
    167     closesocket(sock);
    168     fprintf(stderr, "all done
    ");
    169     libssh2_exit();
    170 
    171     return rc;
    172 }
    173 
    174 long tvdiff(struct timeval newer, struct timeval older)
    175 {
    176     return (newer.tv_sec-older.tv_sec)*1000+(newer.tv_usec-older.tv_usec)/1000;
    177 }
    178 
    179 int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
    180 {
    181     struct timeval timeout;
    182     int ret;
    183     fd_set fd;
    184     fd_set *writefd = NULL;
    185     fd_set *readfd = NULL;
    186     int dir;
    187     timeout.tv_sec = 10;
    188     timeout.tv_usec = 0;
    189     FD_ZERO(&fd);
    190     FD_SET(socket_fd, &fd);
    191     /* now make sure we wait in the correct direction */
    192     dir = libssh2_session_block_directions(session);
    193     if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
    194         readfd = &fd;
    195     if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
    196         writefd = &fd;
    197     ret = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
    198     return ret;
    199 }
    View Code

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

      

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

     1 05-28-2015 14:18:05 HOST localhost SSH connection attempt.
     2 05-28-2015 14:18:05 HOST localhost SSH user successfully logged on using password.
     3 05-28-2015 14:18:06 SFTP service granted to user user.
     4 05-28-2015 14:18:06 HOST localhost user is uploading wunaozai.txt (E:wunaozai.txt)
     5 05-28-2015 14:18:06 HOST localhost SSH user disconnected.
     6 05-28-2015 14:18:23 HOST localhost SSH connection attempt.
     7 05-28-2015 14:18:23 HOST localhost SSH user successfully logged on using password.
     8 05-28-2015 14:18:23 SFTP service granted to user user.
     9 05-28-2015 14:18:23 HOST localhost user is uploading wunaozai.txt (E:wunaozai.txt)
    10 05-28-2015 14:18:23 HOST localhost SSH user disconnected.
    11 05-28-2015 14:18:49 HOST localhost SSH connection attempt.
    12 05-28-2015 14:18:49 HOST localhost SSH user successfully logged on using password.
    13 05-28-2015 14:18:49 SFTP service granted to user user.
    14 05-28-2015 14:18:49 HOST localhost user is uploading wunaozai.txt (E:wunaozai.txt)
    15 05-28-2015 14:18:49 HOST localhost SSH user disconnected.
    16 05-28-2015 14:18:55 HOST localhost SSH connection attempt.
    17 05-28-2015 14:18:56 HOST localhost SSH user successfully logged on using password.
    18 05-28-2015 14:18:56 SFTP service granted to user user.
    19 05-28-2015 14:18:56 HOST localhost user is downloading wunaozai.txt (E:wunaozai.txt)
    20 05-28-2015 14:18:56 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

  • 相关阅读:
    ORA-12560:TNS:协议适配器错误
    oracledbconsole db启动问题
    安装tomcat出现failed to install tomcat6 service错误及解决方法(转载)
    关于Eclipse配置tomcat
    js indexof用法indexOf()定义和用法
    手机被没收事件。。。
    一维数组,求最大子数组!!!
    用n(0)次求一个数组里面最大子数组的和(数组可以输入负数)
    jwt认证
    序列化组件
  • 原文地址:https://www.cnblogs.com/wunaozai/p/4534302.html
Copyright © 2020-2023  润新知