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

0.环境安装

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

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

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

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

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

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

1.示例讲解

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

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

  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 }
View Code

相关文章: