Socket网络编程--FTP客户端

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

  已经很久没有写过博客进行分享了。具体缘由,在之后说。html

  这几天在了解FTP协议,准备任务是写一个FTP客户端程序。直接上干货了。编程

0.了解FTP做用api

  就是一个提供一个文件的共享协议。浏览器

1.了解FTP协议安全

  FTP有指令和响应码。FTP 控制帧即指 TELNET 交换信息,包含 TELNET 命令和选项。然而,大多数 FTP 控制帧是简单的 ASCII 文本,能够分为 FTP 命令或 FTP 消息。 FTP 消息是对 FTP 命令的响应,它由带有解释文本的应答代码构成。服务器

  像这种利用交换信息来进行简单的控制,这种协议,还真的很好玩的说。 命令与响应码部分信息以下网络

  

  

2. 安装一个FTP服务器socket

  咱们先安装一个FTP服务器,用于测试,这里是用FileZilla Server做为FTP服务器。ide

  启动后,增长一个用户user/user函数

3.FTP客户端源代码讲解

  下面这个是FTPAPI.h文件

复制代码
 1 #ifndef FTPAPI_H_INCLUDED  2 #define FTPAPI_H_INCLUDED  3  4 #include <stdio.h>  5 #include <winsock2.h>  6  7 SOCKET socket_connect(char *host, int port);  8 SOCKET connect_server(char *host, int port);  9 int ftp_sendcmd_re(SOCKET sock, char *cmd, char *re_buf, ssize_t *len); 10 int ftp_sendcmd(SOCKET sock, char *cmd); 11 int login_server(SOCKET sock, char *user, char *pwd); 12 void socket_close(int c_sock); 13 14 15 /**********可用命令*********/ 16 SOCKET ftp_connect(char *host, int port, char *user, char *pwd); //链接到服务器 17 int ftp_quit(SOCKET sock); //断开链接 18 int ftp_type(SOCKET sock, char mode); //设置FTP传输类型 19 int ftp_cwd(SOCKET sock, char *path); //更改工做目录 20 int ftp_cdup(SOCKET sock); //回到上级目录 21 int ftp_mkd(SOCKET sock, char *path); //建立目录 22 SOCKET ftp_pasv_connect(SOCKET c_sock); //链接到PASV接口 23 int ftp_list(SOCKET c_sock, char *path, char **data, int *data_len); //列出FTP工做空间的全部目录 24 int ftp_deletefolder(SOCKET sock, char *path); //删除目录 25 int ftp_deletefile(SOCKET sock, char *filename); //删除文件 26 int ftp_renamefile(SOCKET sock, char *s, char *d); //修改文件/目录&移动文件/目录 27 int ftp_server2local(SOCKET c_sock, char *s, char *d, int * size); //从服务器复制文件到本地 RETR 28 int ftp_local2server(SOCKET c_sock, char *s, char *d, int * size); //从本地复制文件到服务器 STOR 29 int ftp_recv(SOCKET sock, char *re_buf, ssize_t *len); //获取响应码 30 31 32 #endif // FTPAPI_H_INCLUDED
复制代码

   下面这个是FTPResponseCode.h 文件 是对应答码简单的描述

复制代码
 1 #ifndef FTPRESPONSECODE_H_INCLUDED  2 #define FTPRESPONSECODE_H_INCLUDED  3  4  5 #define FTP_SUCCESS 200 //成功  6 #define FTP_SERVICE_READY 220 //服务器就绪  7 #define FTP_LOGIN_SUCCESS 230 //登陆因特网服务器  8 #define FTP_FILE_ACTION_COMPLETE 250 //文件行为完成  9 #define FTP_FILE_CREATED 257 //文件建立成功 10 #define FTP_PASSWORD_REQUIREd 331 //要求密码 11 #define FTP_LOGIN_PASSWORD_INCORRECT 530 //用户密码错误 12 13 14 #endif // FTPRESPONSECODE_H_INCLUDED
复制代码

  下面这些是FTPAPI.cpp文件的函数代码

  建立一个socket链接并返回socket套接字 socket_connect

复制代码
 1 /**  2  * 做用: 建立一个Socket并返回.  3  * 参数: IP或域名, 端口  4  * 返回值: Socket套接字  5  * */  6 SOCKET socket_connect(char *host, int port)  7 {  8 int i=0;  9 //初始化 Socket dll 10  WSADATA wsaData; 11 WORD socketVersion = MAKEWORD(2,0); 12 if(WSAStartup(socketVersion, &wsaData)) 13  { 14 printf("Init socket dll error!"); 15 exit(1); 16  } 17 18 struct hostent * server = gethostbyname(host); 19 if(!server) 20 return -1; 21 unsigned char ch[4]; 22 char ip[20]; 23 //一个hostname 能够对应多个ip 24 while(server->h_addr_list[i]!=NULL) 25  { 26 memcpy(&ch,server->h_addr_list[i],4); 27 sprintf(ip,"%d.%d.%d.%d",ch[0],ch[1],ch[2],ch[3]); 28 //printf("%s\n",ip); 29 i++; 30  } 31 32 //建立Socket 33 SOCKET s = socket(AF_INET, SOCK_STREAM, 0); //TCP socket 34 if(SOCKET_ERROR == s) 35  { 36 printf("Create Socket Error!"); 37 exit(1); 38  } 39 //设置超时链接 40 int timeout = 3000; //复杂的网络环境要设置超时判断 41 int ret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)); 42 ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)); 43 //指定服务器地址 44 struct sockaddr_in address; 45 address.sin_family = AF_INET; 46 address.sin_addr.S_un.S_addr = inet_addr(ip); 47 address.sin_port = htons((unsigned short)port); 48 //链接 49 if(SOCKET_ERROR == connect(s,(LPSOCKADDR)&address,sizeof(address))) 50  { 51 printf("Can Not Connect To Server IP!\n"); 52 exit(1); 53  } 54 return s; 55 }
复制代码

  链接到一个ftp服务器 connect_server

复制代码
 1 /**  2  * 做用: 链接到一个FTP服务器,返回socket  3  * 参数: IP或域名, 端口  4  * 返回值: Socket套接字  5  * */  6 SOCKET connect_server(char *host, int port)  7 {  8  SOCKET ctrl_sock;  9 char buf[BUFSIZE]; 10 int result; 11  ssize_t len; 12 13 ctrl_sock = socket_connect(host,port); 14 if(-1 == ctrl_sock) 15  { 16 return -1; 17  } 18 while((len = recv(ctrl_sock, buf, BUFSIZE, 0)) > 0) 19  { 20 //len = recv(ctrl_sock, buf, BUFSIZE, 0); 21 buf[len]=0; 22 printf("%s\n",buf); //220-FileZilla Server version 0.9.43 beta 23  } 24 sscanf(buf, "%d", &result); 25 26 if(FTP_SERVICE_READY != result) 27  { 28 printf("FTP Not ready, Close the socet."); 29 closesocket(ctrl_sock); //关闭Socket 30 return -1; 31  } 32 return ctrl_sock; 33 }
复制代码

  send发送命令,并返回recv结果 ftp_sendcmd_re

复制代码
 1 /**  2  * 做用: send发送命令,并返回recv结果  3  * 参数: SOCKET,命令,命令返回码-命令返回描述,命令返回字节数  4  * 返回值: 0 表示发送成功 -1表示发送失败  5  * */  6 int ftp_sendcmd_re(SOCKET sock, char *cmd, char *re_buf, ssize_t *len)  7 {  8 char buf[BUFSIZE];  9  ssize_t r_len; 10 if(send(sock, cmd, strlen(cmd), 0) == -1) 11  { 12 return -1; 13  } 14 r_len = recv(sock, buf, BUFSIZE, 0); 15 if(r_len < 1) 16 return -1; 17 buf[r_len]=0; 18 if(NULL != len) 19 *len = r_len; 20 if(NULL != re_buf) 21 sprintf(re_buf, "%s", buf); 22 return 0; 23 }
复制代码

  send发送命令 ftp_sendcmd

复制代码
 1 /**  2  * 做用: send发送命令  3  * 参数: SOCKET,命令  4  * 返回值: FTP响应码  5  * */  6 int ftp_sendcmd(SOCKET sock, char *cmd)  7 {  8 char buf[BUFSIZE];  9 int result; 10  ssize_t len; 11 printf("FTP Client: %s", cmd); 12 result = ftp_sendcmd_re(sock, cmd, buf, &len); 13 printf("FTP Server: %s", buf); 14 if(0 == result) 15  { 16 sscanf(buf, "%d", &result); 17  } 18 return result; 19 }
复制代码

  登陆FTP服务器 login_server

复制代码
 1 /**  2  * 做用: 登陆FTP服务器  3  * 参数: SOCKET套接字,明文用户名,明文密码  4  * 返回值: 0 表示登陆成功 -1 表示登陆失败  5  * */  6 int login_server(SOCKET sock, char *user, char *pwd)  7 {  8 char buf[BUFSIZE];  9 int result; 10 sprintf(buf, "USER %s\r\n", user); 11 //这里要对socket进行阻塞 12 int timeout=0; 13 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)); 14 result = ftp_sendcmd(sock, buf); 15 if(FTP_LOGIN_SUCCESS == result) //直接登陆 16 return 0; 17 else if(FTP_PASSWORD_REQUIREd == result) //须要密码 18  { 19 sprintf(buf, "PASS %s\r\n", pwd); 20 result = ftp_sendcmd(sock, buf); 21 if(FTP_LOGIN_SUCCESS == result) 22  { 23 return 0; 24  } 25 else //530 密码错误 26  { 27 return -1; 28  } 29  } 30 else 31  { 32 return -1; 33  } 34 }
复制代码

  winsock使用后,要调用WSACleanup函数关闭网络设备 socket_close

复制代码
1 /** 2  * 做用: winsock使用后,要调用WSACleanup函数关闭网络设备,以便释放其占用的资源 3  * 参数: SOCKET 4  * 返回值: 无 5  * */ 6 void socket_close(int c_sock) 7 { 8  WSACleanup(); 9 }
复制代码

  链接到FTP服务器 ftp_connect

复制代码
 1 /**  2  * 做用: 链接到FTP服务器  3  * 参数: hostname或IP,端口,用户名,密码  4  * 返回值: 已链接到FTP服务器的SOCKET -1 表示登陆失败  5  * */  6 SOCKET ftp_connect(char *host, int port, char *user, char *pwd)  7 {  8  SOCKET sock;  9 sock = connect_server(host, port); 10 if(-1 == sock) 11  { 12 return -1; 13  } 14 if(-1 == login_server(sock, user, pwd)) 15  { 16  closesocket(sock); 17 return -1; 18  } 19 return sock; 20 }
复制代码

  断开FTP服务器 ftp_quit

复制代码
 1 /**  2  * 做用: 断开FTP服务器  3  * 参数: SOCKET  4  * 返回值: 成功断开状态码  5  * */  6 int ftp_quit(SOCKET sock)  7 {  8 int result = 0;  9 result = ftp_sendcmd(sock, "QUIT\r\n"); 10  closesocket(sock); 11  socket_close(sock); 12 return result; 13 }
复制代码

  设置FTP传输类型 A:ascii I:Binary  ftp_type

复制代码
 1 /**  2  * 做用: 设置FTP传输类型 A:ascii I:Binary  3  * 参数: SOCkET,类型  4  * 返回值: 0 表示成功 -1 表示失败  5  * */  6 int ftp_type(SOCKET sock, char mode)  7 {  8 char buf[BUFSIZ];  9 sprintf(buf,"TYPE %c\r\n", mode); 10 if(FTP_SUCCESS != ftp_sendcmd(sock, buf)) 11 return -1; 12 else 13 return 0; 14 }
复制代码

  更改工做目录 ftp_cwd

复制代码
 1 /**  2  * 做用: 更改工做目录  3  * 参数: SOCKET,工做目录  4  * 返回值: 0 表示成功 -1 表示失败  5  * */  6 int ftp_cwd(SOCKET sock, char *path)  7 {  8 char buf[BUFSIZE];  9 int result; 10 sprintf(buf, "CWD %s\r\n", path); 11 result = ftp_sendcmd(sock, buf); 12 if(FTP_FILE_ACTION_COMPLETE != result) //250 文件行为完成 13 return -1; 14 else 15 return 0; 16 }
复制代码

  回到上级目录 ftp_cdup

复制代码
 1 /**  2  * 做用: 回到上级目录  3  * 参数: SOCKET  4  * 返回值: 0 正常操做返回 result 服务器返回响应码  5  * */  6 int ftp_cdup(SOCKET sock)  7 {  8 int result;  9 result = ftp_sendcmd(sock, "CDUP\r\n"); 10 if(FTP_FILE_ACTION_COMPLETE == result || FTP_SUCCESS == result) 11 return 0; 12 else 13 return result; 14 }
复制代码

  建立目录 ftp_mkd

复制代码
 1 /**  2  * 做用: 建立目录  3  * 参数: SOCKET,文件目录路径(可相对路径,绝对路径)  4  * 返回值: 0 正常操做返回 result 服务器返回响应码  5  * */  6 int ftp_mkd(SOCKET sock, char *path)  7 {  8 char buf[BUFSIZE];  9 int result; 10 sprintf(buf, "MKD %s\r\n", path); 11 result = ftp_sendcmd(sock, buf); 12 if(FTP_FILE_CREATED != result) //257 路径名创建 13 return result; //550 目录已存在 14 else 15 return 0; 16 }
复制代码

  链接到PASV接口 ftp_pasv_connect

复制代码
 1 /**  2  * 做用: 链接到PASV接口  3  * PASV(被动)方式的链接过程是:  4  * 客户端向服务器的FTP端口(默认是21)发送链接请求,  5  * 服务器接受链接,创建一条命令链路。  6  * 参数: 命令链路SOCKET cmd-socket  7  * 返回值: 数据链路SOCKET raw-socket -1 表示建立失败  8  * */  9 SOCKET ftp_pasv_connect(SOCKET c_sock) 10 { 11  SOCKET r_sock; 12 int send_result; 13  ssize_t len; 14 int addr[6]; //IP*4+Port*2 15 char buf[BUFSIZE]; 16 char result_buf[BUFSIZE]; 17 18 //设置PASV被动模式 19 memset(buf,sizeof(buf),0); 20 sprintf(buf, "PASV\r\n"); 21 send_result = ftp_sendcmd_re(c_sock, buf, result_buf, &len); 22 if(send_result == 0) 23  { 24 sscanf(result_buf, "%*[^(](%d,%d,%d,%d,%d,%d)", 25 &addr[0],&addr[1],&addr[2],&addr[3], 26 &addr[4],&addr[5]); 27  } 28 29 //链接PASV端口 30 memset(buf, sizeof(buf), 0); 31 sprintf(buf, "%d.%d.%d.%d",addr[0],addr[1],addr[2],addr[3]); 32 r_sock = socket_connect(buf,addr[4]*256+addr[5]); 33 if(-1 == r_sock) 34 return -1; 35 return r_sock; 36 }
复制代码

  列出FTP工做空间的全部目录 ftp_list

复制代码
 1 /**  2  * 做用: 列出FTP工做空间的全部目录  3  * 参数: 命令链路SOCKET,工做空间,列表信息,列表信息大小  4  * 返回值: 0 表示列表成功 result>0 表示其余错误响应码 -1 表示建立pasv错误  5  * */  6 int ftp_list(SOCKET c_sock, char *path, char **data, int *data_len)  7 {  8  SOCKET r_sock;  9 char buf[BUFSIZE]; 10 int send_re; 11 int result; 12  ssize_t len,buf_len,total_len; 13 14 //链接到PASV接口 15 r_sock = ftp_pasv_connect(c_sock); 16 if(-1 == r_sock) 17  { 18 return -1; 19  } 20 //发送LIST命令 21 memset(buf,sizeof(buf),0); 22 sprintf(buf, "LIST %s\r\n", path); 23 send_re = ftp_sendcmd(c_sock, buf); 24 if(send_re >= 300 || send_re == 0) 25 return send_re; 26 len=total_len=0; 27 buf_len=BUFSIZE; 28 char *re_buf = (char *)malloc(buf_len); 29 while( (len = recv(r_sock,buf,BUFSIZE,0)) > 0) 30  { 31 if(total_len+len > buf_len) 32  { 33 buf_len *= 2; 34 char *re_buf_n = (char *)malloc(buf_len); 35  memcpy(re_buf_n, re_buf, total_len); 36 free(re_buf); 37 re_buf = re_buf_n; 38  } 39 memcpy(re_buf+total_len, buf, len); 40 total_len += len; 41  } 42  closesocket(r_sock); 43 44 //向服务器接收返回值 45 memset(buf, sizeof(buf), 0); 46 len = recv(c_sock, buf, BUFSIZE, 0); 47 buf[len] = 0; 48 sscanf(buf, "%d", &result); 49 if(result != 226) 50  { 51 free(re_buf); 52 return result; 53  } 54 *data = re_buf; 55 *data_len = total_len; 56 return 0; 57 }
复制代码

  删除目录 ftp_deletefolder

复制代码
 1 /**  2  * 做用: 删除目录  3  * 参数: 命令链路SOCKET,路径目录  4  * 返回值: 0 表示列表成功 result>0 表示其余错误响应码  5  * */  6 int ftp_deletefolder(SOCKET sock, char *path)  7 {  8 char buf[BUFSIZE];  9 int result; 10 sprintf(buf,"RMD %s\r\n", path); 11 result = ftp_sendcmd(sock, buf); 12 if(FTP_FILE_ACTION_COMPLETE != result) 13  { 14 //550 Directory not empty. 15 //550 Directory not found. 16 return result; 17  } 18 return 0; 19 }
复制代码

  删除文件 ftp_deletefile

复制代码
 1 /**  2  * 做用: 删除文件  3  * 参数: 命令链路SOCKET,路径文件(相对/绝对)  4  * 返回值: 0 表示列表成功 result>0 表示其余错误响应码  5  * */  6 int ftp_deletefile(SOCKET sock, char *filename)  7 {  8 char buf[BUFSIZE];  9 int result; 10 sprintf(buf, "DELE %s\r\n", filename); 11 result = ftp_sendcmd(sock, buf); 12 if(FTP_FILE_ACTION_COMPLETE != 250) //250 File deleted successfully 13  { 14 //550 File not found. 15 return result; 16  } 17 return 0; 18 }
复制代码

  修改文件名&移动目录 ftp_renamefile

复制代码
 1 /**  2  * 做用: 修改文件名&移动目录  3  * 参数: 命令链路SOCKET,源地址,目的地址  4  * 返回值: 0 表示列表成功 result>0 表示其余错误响应码  5  * */  6 int ftp_renamefile(SOCKET sock, char *s, char *d)  7 {  8 char buf[BUFSIZE];  9 int result; 10 sprintf(buf, "RNFR %s\r\n", s); 11 result = ftp_sendcmd(sock, buf); 12 if(350 != result) //350 文件行为暂停,由于要进行移动操做 13 return result; 14 sprintf(buf, "RNTO %s\r\n", d); 15 result = ftp_sendcmd(sock, buf); 16 if(FTP_FILE_ACTION_COMPLETE != result) 17  { 18 return result; 19  } 20 return 0; 21 }
复制代码

  从服务器复制文件到本地 RETR  ftp_server2local

复制代码
 1 /**  2  * 做用: 从服务器复制文件到本地 RETR  3  * 参数: SOCKET,源地址,目的地址,文件大小  4  * 返回值: 0 表示列表成功 result>0 表示其余错误响应码  5  * -1:文件建立失败 -2 pasv接口错误  6  * */  7 int ftp_server2local(SOCKET c_sock, char *s, char *d, int * size)  8 {  9  SOCKET d_sock; 10  ssize_t len,write_len; 11 char buf[BUFSIZ]; 12 int result; 13 *size=0; 14 //打开本地文件 15 FILE * fp = fopen(d, "wb"); 16 if(NULL == fp) 17  { 18 printf("Can't Open the file.\n"); 19 return -1; 20  } 21 //设置传输模式 22 ftp_type(c_sock,'I'); 23 24 //链接到PASV接口 用于传输文件 25 d_sock = ftp_pasv_connect(c_sock); 26 if(-1 == d_sock) 27  { 28 fclose(fp); //关闭文件 29 return -2; 30  } 31 32 //发送RETR命令 33 memset(buf, sizeof(buf), 0); 34 sprintf(buf, "RETR %s\r\n", s); 35 result = ftp_sendcmd(c_sock, buf); 36 // 150 Opening data channel for file download from server of "xxxx" 37 if(result >= 300 || result == 0) //失败多是没有权限什么的,具体看响应码 38  { 39  fclose(fp); 40 return result; 41  } 42 43 //开始向PASV读取数据(下载) 44 memset(buf, sizeof(buf), 0); 45 while((len = recv(d_sock, buf, BUFSIZE, 0)) > 0 ) 46  { 47 write_len = fwrite(&buf, len, 1, fp); 48 if(write_len != 1) //写入文件不完整 49  { 50 closesocket(d_sock); //关闭套接字 51 fclose(fp); //关闭文件 52 return -1; 53  } 54 if(NULL != size) 55  { 56 *size += write_len; 57  } 58  } 59 //下载完成 60  closesocket(d_sock); 61  fclose(fp); 62 63 //向服务器接收返回值 64 memset(buf, sizeof(buf), 0); 65 len = recv(c_sock, buf, BUFSIZE, 0); 66 buf[len] = 0; 67 printf("%s\n",buf); 68 sscanf(buf, "%d", &result); 69 if(result >= 300) 70 { 71 return result; 72 } 73 //226 Successfully transferred "xxxx" 74 return 0; 75 }
复制代码

  从本地复制文件到服务器 STOR ftp_local2server

复制代码
 1 /**  2  * 做用: 从本地复制文件到服务器 STOR  3  * 参数: SOCKET,源地址,目的地址,文件大小  4  * 返回值: 0 表示列表成功 result>0 表示其余错误响应码  5  * -1:文件建立失败 -2 pasv接口错误  6  * */  7 int ftp_local2server(SOCKET c_sock, char *s, char *d, int * size)  8 {  9  SOCKET d_sock; 10  ssize_t len,send_len; 11 char buf[BUFSIZE]; 12 FILE * fp; 13 int send_re; 14 int result; 15 //打开本地文件 16 fp = fopen(s, "rb"); 17 if(NULL == fp) 18  { 19 printf("Can't Not Open the file.\n"); 20 return -1; 21  } 22 //设置传输模式 23 ftp_type(c_sock, 'I'); 24 //链接到PASV接口 25 d_sock = ftp_pasv_connect(c_sock); 26 if(d_sock == -1) 27  { 28  fclose(fp); 29 return -1; 30  } 31 32 //发送STOR命令 33 memset(buf, sizeof(buf), 0); 34 sprintf(buf, "STOR %s\r\n", d); 35 send_re = ftp_sendcmd(c_sock, buf); 36 if(send_re >= 300 || send_re == 0) 37  { 38  fclose(fp); 39 return send_re; 40  } 41 42 //开始向PASV通道写数据 43 memset(buf, sizeof(buf), 0); 44 while( (len = fread(buf, 1, BUFSIZE, fp)) > 0) 45  { 46 send_len = send(d_sock, buf, len, 0); 47 if(send_len != len) 48  { 49  closesocket(d_sock); 50  fclose(fp); 51 return -1; 52  } 53 if(NULL != size) 54  { 55 *size += send_len; 56  } 57  } 58 //完成上传 59  closesocket(d_sock); 60  fclose(fp); 61 62 //向服务器接收响应码 63 memset(buf, sizeof(buf), 0); 64 len = recv(c_sock, buf, BUFSIZE, 0); 65 buf[len] = 0; 66 sscanf(buf, "%d", &result); 67 if(result >= 300) 68  { 69 return result; 70 } 71 return 0; 72 }
复制代码

  获取一行响应码 ftp_recv

复制代码
 1 /**  2  * 做用: 获取一行响应码  3  * 参数:  4  * 返回值:  5  * */  6 int ftp_recv(SOCKET sock, char *re_buf, ssize_t *len)  7 {  8 char buf[BUFSIZE];  9  ssize_t r_len; 10 int timeout = 3000; 11 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); 12 r_len = recv(sock, buf, BUFSIZE, 0); 13 timeout = 0; 14 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); 15 if(r_len < 1) 16 return -1; 17 buf[r_len]=0; 18 if(NULL != len) 19 *len = r_len; 20 if(NULL != re_buf) 21 sprintf(re_buf, "%s", buf); 22 return 0; 23 }
复制代码

 

 4.测试ftp客户端

  下载文件到本地

1     SOCKET s = ftp_connect("127.0.0.1",21,"user","user"); //登陆到FTP服务器 2 int ret = ftp_server2local(s,"user/user.zip","bin.zip",&size); //在FTP服务器获取文件 3 ftp_quit(s); //退出FTP服务器

  上传文件到服务器

1     SOCKET s = ftp_connect("127.0.0.1",21,"user","user"); //登陆到FTP服务器 2 int ret = ftp_local2server(s,"user/user.zip","bin.zip",&size); //发送文件到FTP服务器 3 ftp_quit(s); //退出FTP服务器

  下面这个是服务器的日志信息

  

  下面这个是程序打印的调试信息

   

 

5.后话

  到这里这个简单的ftp库就能够实现绝大部分的客户端功能了,可是这里面有一个问题,就是ftp是明文传输用户名/密码的,若是ftp上的文件比较重要的话,那么就有点问题了。固然这个不是本次的关注点,本次主要是了解ftp协议,还有从代码中了解这种交换控制命令的方法是一种很不错的技术手段,虽然这种方法已是好多年前的,不安全,也过期了。但仍是有可学的地方。

6.附录

  下面这个附录是利用wireshark进行本地网络抓包测试。

一、抓包,要看部署点,在路由器、交换机等设备上作端口镜像、或分光口,或是接HUB、TAP等设备就能够直接得到经过这些口的报文。
二、抓包,也可在以局域网部署相关的网管软件或黑客工具(好比cain),能够用arp骗方式,让你的数据先发送到监控机上,而后再转发走。。这样你的数据就。。

建议:
一、建议在电脑上打开ARP防御功能
二、在使用中尽可能使用加密传输的工具,好比SSH、SSL、QQ一类的东西。可避免一些危害.

  注意wireshark是不能抓取本地回环地址的数据包的,因此我以远程ftp服务器进行测试

   

  这里是经过浏览器进行链接的。wireshark 1.12.4 从上面能够看到的信息 29-44这些表示 了,浏览器一开始使用匿名进行登陆,发现登陆不上,因此请求用户名登陆在81 82 84 85这4行中咱们能够分析到,我是输入用户名user 密码user进行登陆的,第106行表示用户名/密码错误。 若是是230 Login in 就表示成功登陆了。若是咱们捉到了这些信息,那么咱们就能够进行登陆了。这样就不安全了。既然ftp这么不安全为何那么多地方用到ftp共享文件。这个 就要说到ftp的做用了,ftp做用原本就是共享文件,因此安全性就不是很重要了。 至于加密方式之后再讲。

   (开发环境mignw 编译的时候要加入libws2_32.a 这个库, 编译命令 g++ ftpapi.cpp -c -o ftpapi.o -lws2_32)

 

 

  参考资料

  TanHao的 THFTPAPI.c 文件 http://www.tanhao.me

  文件下载 ftpapi.zip http://files.cnblogs.com/files/wunaozai/ftpapi20150512.zip 

做者:无脑仔的小明
出处:http://www.cnblogs.com/wunaozai/ 本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。 若是文中有什么错误,欢迎指出。以避免更多的人被误导。
相关文章
相关标签/搜索