博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Socket网络编程--FTP客户端(2)(Windows)
阅读量:6173 次
发布时间:2019-06-21

本文共 27361 字,大约阅读时间需要 91 分钟。

   上一篇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 
12 #include
13 14 #ifdef HAVE_WINSOCK2_H 15 # include
16 #endif 17 #ifdef HAVE_SYS_SOCKET_H 18 # include
19 #endif 20 #ifdef HAVE_NETINET_IN_H 21 # include
22 #endif 23 #ifdef HAVE_SYS_SELECT_H 24 # include
25 #endif 26 # ifdef HAVE_UNISTD_H 27 #include
28 #endif 29 #ifdef HAVE_ARPA_INET_H 30 # include
31 #endif 32 #ifdef HAVE_SYS_TIME_H 33 # include
34 #endif 35 36 #include
37 #include
38 #include
39 #include
40 #include
41 #include
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 #endif105 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 socket139 * and establishing the connection140 */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 layers162 */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 is171 * check the hostkey's fingerprint against our known hosts Your app may172 * have it hard coded, may go to a file, may present it to the user,173 * that's your call174 */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 WIN32275 closesocket(sock);276 #else277 close(sock);278 #endif279 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 
12 #include
13 14 #ifdef HAVE_WINSOCK2_H 15 # include
16 #endif 17 #ifdef HAVE_SYS_SOCKET_H 18 # include
19 #endif 20 #ifdef HAVE_NETINET_IN_H 21 # include
22 #endif 23 #ifdef HAVE_SYS_SELECT_H 24 # include
25 #endif 26 # ifdef HAVE_UNISTD_H 27 #include
28 #endif 29 #ifdef HAVE_ARPA_INET_H 30 # include
31 #endif 32 #ifdef HAVE_SYS_TIME_H 33 # include
34 #endif 35 36 #include
37 #include
38 #include
39 #include
40 #include
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 #endif108 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 socket133 * and establishing the connection134 */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 layers158 */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 do167 * is check the hostkey's fingerprint against our known hosts Your app168 * may have it hard coded, may go to a file, may present it to the169 * user, that's your call170 */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 0202 libssh2_trace(session, LIBSSH2_TRACE_CONN);203 #endif204 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 WIN32274 closesocket(sock);275 #else276 close(sock);277 #endif278 fprintf(stderr, "all done\n");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 
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
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 
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
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这个文件,没有的话可以在代码中注释掉.

  

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

   

 

  本文地址:

你可能感兴趣的文章
Supported plattforms
查看>>
做自己喜欢的事情
查看>>
CRM安装(二)
查看>>
Eclipse工具进行Spring开发时,Spring配置文件智能提示需要安装STS插件
查看>>
NSURLCache内存缓存
查看>>
jquery click嵌套 事件重复注册 多次执行的问题
查看>>
Dev GridControl导出
查看>>
开始翻译Windows Phone 8 Development for Absolute Beginners教程
查看>>
Python tablib模块
查看>>
站立会议02
查看>>
Windows和Linux如何使用Java代码实现关闭进程
查看>>
0428继承性 const static
查看>>
第一课:从一个简单的平方根运算学习平方根---【重温数学】
查看>>
NET反射系统
查看>>
Oracle12C本地用户的创建和登录
查看>>
使用JS制作一个鼠标可拖的DIV(一)——鼠标拖动
查看>>
HDU problem 5635 LCP Array【思维】
查看>>
leetcode10. 正则表达式匹配
查看>>
redis常用命令--zsets
查看>>
springcloud--Feign(WebService客户端)
查看>>