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\n", 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)\n", rc);
128         return 1;
129     }
130
131     local = fopen(loclfile, "rb");
132     if (!local) {
133         fprintf(stderr, "Can‘t open local file %s\n", 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!\n");
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\n", 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, "\n");
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.\n");
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, "\tAuthentication by public key failed\n");
199             goto shutdown;
200         }
201     }
202
203     fprintf(stderr, "libssh2_sftp_init()!\n");
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\n");
210             goto shutdown;
211         }
212     } while (!sftp_session);
213
214     fprintf(stderr, "libssh2_sftp_open()!\n");
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\n");
226             goto shutdown;
227         }
228     } while (!sftp_handle);
229
230     fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
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\n",
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\n");
280
281     libssh2_exit();
282
283     return 0;
284 }

  下面这个是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\n", 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)\n", 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!\n");
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\n", 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, "\n");
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.\n");
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, "\tAuthentication by public key failed\n");
198             goto shutdown;
199         }
200     }
201 #if 0
202     libssh2_trace(session, LIBSSH2_TRACE_CONN);
203 #endif
204     fprintf(stderr, "libssh2_sftp_init()!\n");
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\n");
212                 waitsocket(sock, session); /* now we wait */
213             }
214             else {
215                 fprintf(stderr, "Unable to init SFTP session\n");
216                 goto shutdown;
217             }
218         }
219     } while (!sftp_session);
220
221     fprintf(stderr, "libssh2_sftp_open()!\n");
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\n");
230                 goto shutdown;
231             }
232             else {
233                 fprintf(stderr, "non-blocking open\n");
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!\n");
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\n", 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\n");
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\n");
279
280     libssh2_exit();
281
282     return 0;
283 }

  上面一个是发送文件到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\n", err);
 46         return 1;
 47     }
 48
 49     rc = libssh2_init (0);
 50     if (rc != 0) {
 51         fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
 52         return 1;
 53     }
 54
 55     local = fopen(LOCLFILE, "rb");
 56     if (!local) {
 57         fprintf(stderr, "Can‘t open local file %s\n", 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!\n");
 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\n", 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, "\n");
 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.\n");
105         goto shutdown;
106     }
107
108     //fprintf(stderr, "libssh2_sftp_init()!\n");
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\n");
113             goto shutdown;
114         }
115     } while (!sftp_session);
116     //fprintf(stderr, "libssh2_sftp_open()!\n");
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\n"); //可能是没有写入权限,或者没有对应的目录
128             goto shutdown;
129         }
130     } while (!sftp_handle);
131
132     fprintf(stderr, "libssh2_sftp_open() is done, now send data!\n");
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\n", 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\n");
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 }

  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\n", ret);
 45         return 1;
 46     }
 47
 48     ret = libssh2_init (0);
 49     if (ret != 0) {
 50         fprintf (stderr, "libssh2 initialization failed (%d)\n", 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!\n");
 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\n", 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, "\n");
 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.\n");
 88         goto shutdown2;
 89     }
 90
 91     fprintf(stderr, "libssh2_sftp_init()!\n");
 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\n");
 97                 waitsocket(sock, session); /* now we wait */
 98             }
 99             else {
100                 fprintf(stderr, "Unable to init SFTP session\n");
101                 goto shutdown2;
102             }
103         }
104     } while (!sftp_session);
105
106     fprintf(stderr, "libssh2_sftp_open()!\n");
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\n");
115                 goto shutdown2;
116             }
117             else {
118                 fprintf(stderr, "non-blocking open\n");
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\n",LOCLFILE);
130         return -1;
131     }
132     fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
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\n", 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\n");
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\n");
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 }

  至于用到的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

时间: 2024-11-05 17:33:07

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

Socket网络编程初探

MarkdownPad Document Socket网络编程初探 客户端/服务器架构 即C/S架构,其实web服务在某种意义上也算是C/S架构 一个特点是服务器端持续运行对外提供服务 为何学习socket一定要先学习互联网协议: C/S架构的软件是基于网络进行通信的 网络的核心就是一堆协议,即标准,想要开发一款基于网络通信的软件就必须遵循这些标准 socket是处在应用层和传输层中间的一组接口 说到这,那么socket到底是个什么呢?Socket是应用层与TCP/IP协议族通信的中间软件抽象层

socket 网络编程快速入门(一)教你编写基于UDP/TCP的服务(客户端)通信

因为UNIX和Win的socket大同小异,为了方便和大众化,这里先介绍Winsock编程. socket 网络编程的难点在入门的时候就是对基本函数的了解和使用,因为这些函数的结构往往比较复杂,参数大部分都是结构体,令人难以记忆和理解. 但是一旦我们知道这些函数包括其参数的具体含义,socket网络编程也就变得不是那么复杂.这里不赘述 具体函数的详细含义,网络上有很多的文章,同时笔者建议大家参考 MSDN,对返回值,参数等会有更好的理解. 以下均为单线程的简单实例,多线程的请关注下一篇文章. (

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

windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先写了个简单的winSocket网路通信的例子,以便以后用到的时候有个参考. windows下使用winsock编程与linux/unix的区别在于windows下需要先有一个初始化的操作,结束的时候需要一个清理的操作.还有windows下编译的时候需要连接ws32_lib库. 大致过程如下 1.初始

windows下的socket网络编程

windows下的socket网络编程 windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先写了个简单的winSocket网路通信的例子,以便以后用到的时候有个参考. windows下使用winsock编程与linux/unix的区别在于windows下需要先有一个初始化的操作,结束的时候需要一个清理的操作.还有windows下编译的时候需要连接ws

Socket网络编程TCP、UDP示例

Socket网络编程: 1) OSI(了解): 国际标准化组织ISO(International Orgnization for Standardization)指定了网络通信的模型:开放系统互联(OSI,Open System Interconnection),把网络通信工作分为七层:物理层(最底层)-数据链路层-网络层-传输层-会话层-表示层-应用层(应用程序) 数据格式 功能与连接方式 典型设备 应用层 网络服务与使用者应用程序间的一个接口 表示层 数据表示.数据安全.数据压缩 会话层 建

Socket网络编程TCP、UDP演示样例

Socket网络编程: 1) OSI(了解): 国际标准化组织ISO(International Orgnization for Standardization)指定了网络通信的模型:开放系统互联(OSI,Open System Interconnection),把网络通信工作分为七层:物理层(最底层)-数据链路层-网络层-传输层-会话层-表示层-应用层(应用程序) 数据格式 功能与连接方式 典型设备 应用层 网络服务与使用者应用程序间的一个接口 表示层 数据表示.数据安全.数据压缩 会话层 建

Socket网络编程(TCP/IP/端口/类)和实例

Socket网络编程(TCP/IP/端口/类)和实例 原文:C# Socket网络编程精华篇 转自:微冷的雨 我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念: TCP/IP层次模型 当然这里我们只讨论重要的四层 01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业应用和互联网应用.http协议在应用层运行. 02,传输层(Tanspot):传输层包括UDP和TCP,UDP几乎不对报文进行检查,而

嵌入式 Linux网络编程(一)——Socket网络编程基础

嵌入式 Linux网络编程一--Socket网络编程基础 一.Socket简介 1.网络中进程间通信 本机进程使用进程号区别不同的进程进程间通信方式有管道.信号.消息队列.共享内存.信号量等.网络中进程间的通信首先需要识别进程所在主机在网络中的唯一标识即网络层的IP地址主机上的进程可以通过传输层的协议与端口号识别. 2.Socket原理 Socket是应用层与TCP/IP协议族通信的中间软件抽象层是一种编程接口.Socket屏蔽了不同网络协议的差异支持面向连接(Transmission Cont

Socket网络编程--小小网盘程序(4)

在这一小节中实现了文件的下载,具体的思路是根据用户的uid和用户提供的文件名filename联合两张表,取得md5唯一标识符,然后操作这个标识符对应的文件发送给客户端. 实现下载的小小网盘程序 client.cpp增加下面这个函数以实现文件的下载. 1 int file_pull(struct Addr addr,struct User user,char *filenames) 2 { 3 struct sockaddr_in servAddr; 4 struct hostent *host;