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

  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

  下面这个是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 }
View Code

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

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

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

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

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

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

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

 

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

你可能感兴趣的:(windows)