Socket网络编程--FTP客户端
Socket网络编程--FTP客户端(1)(Windows)
已经好久没有写过博客进行分享了。具体原因,在以后说。
这几天在了解FTP协议,准备任务是写一个FTP客户端程序。直接上干货了。
0.了解FTP作用
就是一个提供一个文件的共享协议。
1.了解FTP协议
FTP有指令和响应码。FTP 控制帧即指 TELNET 交换信息,包含 TELNET 命令和选项。然而,大多数 FTP 控制帧是简单的 ASCII 文本,可以分为 FTP 命令或 FTP 消息。 FTP 消息是对 FTP 命令的响应,它由带有解释文本的应答代码构成。
像这种利用交换信息来进行简单的控制,这种协议,还真的很好玩的说。 命令与响应码部分信息如下
2. 安装一个FTP服务器
我们先安装一个FTP服务器,用于测试,这里是用FileZilla Server作为FTP服务器。
启动后,增加一个用户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进行本地网络抓包测试。
1、抓包,要看部署点,在路由器、交换机等设备上做端口镜像、或分光口,或是接HUB、TAP等设备就可以直接获得通过这些口的报文。
2、抓包,也可在以局域网部署相关的网管软件或黑客工具(比如cain),可以用arp骗方式,让你的数据先发送到监控机上,然后再转发走。。这样你的数据就。。建议:
1、建议在电脑上打开ARP防护功能
2、在使用中尽量使用加密传输的工具,比如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/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。 |
Socket网络编程--FTP客户端的更多相关文章
- Socket网络编程--FTP客户端(1)(Windows)
已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...
- Socket网络编程--FTP客户端(60篇socket博客,而且都比较简单、深入浅出)
已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解FTP作用 就是一个提供一个文件的共享协议. 1.了解FTP协议 ...
- Socket网络编程--FTP客户端(2)(Windows)
上一篇FTP客户端讲到如果制作一个简单的FTP客户端,功能实现了,但是后面我们发现了问题,就是FTP是使用明文进行操作的.对于普通情况来说就无所谓了.但有时候要安全的一点的话,就应该使用FTP的安全版 ...
- 基于Socket网络编程
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a2011480169/article/details/73602708 博客核心内容: 1.Sock ...
- 循序渐进Socket网络编程(多客户端、信息共享、文件传输)
循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...
- Python Socket 网络编程 (客户端的编程)
Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...
- Python全栈【Socket网络编程】
Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...
- Socket网络编程-基础篇
Socket网络编程 网络通讯三要素: IP地址[主机名] 网络中设备的标识 本地回环地址:127.0.0.1 主机名:localhost 端口号 用于标识进程的逻辑地址 有效端口:0~65535 其 ...
- Socket网络编程详解
一,socket的起源 socket一词的起源 在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的, 撰写者为Stephen Carr.Steve Crocker和Vi ...
随机推荐
- SQLHelp帮助类
public readonly static string connStr = ConfigurationManager.ConnectionStrings["conn"].Con ...
- x01.Game.Main: 从零开始
一切从零开始,一切皆有可能. 浅墨,90后,<逐梦之旅>深入浅出,堪比大师. 1.安装 DXSDK_June10.exe 或更新版本. 2.运行 vs2012,新建 VC Win32 空项 ...
- ssh升级
Openssh升级操作步骤(此方法仅供参考) 1 .开启telnet服务 未避免openssh升级失败,导致ssh无法连接,在升级前首先开启telnet服务. 首先要确定是否安装了telnet 修改配 ...
- 启动mysql错误ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)
ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ ( ...
- [转]SQL 操作结果集 -并集、差集、交集、结果集排序
本文转自:http://www.cnblogs.com/kissdodog/archive/2013/06/24/3152743.html 操作结果集 为了配合测试,特地建了两个表,并且添加了一些测试 ...
- 洛谷P1126机器人搬重物[BFS]
题目描述 机器人移动学会(RMI)现在正尝试用机器人搬运物品.机器人的形状是一个直径1.6米的球.在试验阶段,机器人被用于在一个储藏室中搬运货物.储藏室是一个N*M的网格,有些格子为不可移动的障碍.机 ...
- Github 扩展推荐
前言 github是个知识的宝库,分享一下自己浏览github使用的浏览器扩展. octotree 功能简介:以文件组织的结构方式查看仓库,再也不用一级一级地翻目录啦.下载单个文件 源码:https: ...
- Hash MD5 CRC 知识
本文旨在科普安全相关的知识,并附一个C#实现的文件管理工具. Hash 安全散列算法(英语:Secure Hash Algorithm,缩写为SHA)是一个密码散列函数家族,是FIPS所认证的五种安全 ...
- div根据内容改变大小并且左右居中
div{ display:inline-block; width:auto; } 这个div的父元素text-align:center;
- java 22 - 14 JDK1.5以后的Lock锁
在之前解决线程安全的过程中,虽然我们可以理解同步代码块和同步方法的锁对象问题, 但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁, 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对 ...