miniFTP项目实战一
项目简介:
在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务进程来为客户提供服务。同时每个ftp服务进程配套了nobody进程(内部私有进程),主要是为了做权限提升和控制。
实现功能:
除了基本的文件上传和下载功能,还实现模式选择、断点续传、限制连接数、空闲断开、限速等功能。
用到的技术:
socket、I/O复用、进程间通信、HashTable
欢迎技术交流q:2723808286
项目开源!!!
miniFTP项目实战一
miniFTP项目实战二
miniFTP项目实战三
miniFTP项目实战四
miniFTP项目实战五
miniFTP项目实战六
文章目录
一.FTP协议
1.1 FTP简介
File Transfer Protocol (文件传输协议),FTP是工作在TCP/IP协议簇的应用层,传输层使用TCP,基于客户/服务器模式工作。
vsftpd 是“ very secure FTP daemon ”的缩写,安全性是它的一个最大的特点。 vsftpd是一个 UNIX 类操作系统上运行的服务器的名字,它可以运行在诸如 Linux 、 BSD 、 Solaris 、HP UNIX 等系统上面,是一个完全免费的、开放源代码的 ftp 服务器软件,支持很多其他的FTP 服务器所不支持的特征。
1.2 FTP 支持的文件类型
目前主要使用ASCII文件与图像文件,也就是传输的文件类型:
- ASCII码文件
- 二进制文件
两者的差别是:
- ASCII码的组成是7个比特位,最高位总是0。如果将二进制文件解释为ASCII文件时,最高为会不确定是否为0.
- 不同系统换行符不同,win中换行符为
\r\n
,linux中为\n
,mac中为\r
。这对于以ASCII形式传输文件时有影响,以ASCII传输文件时从win到linux会将文件中\r\n转换为\n,从linux到win会将\n转换为\r\n。但是如果以二进制方式传输的话,不会有不同系统传输文件时的换行符差别。
所以一般情况下是以二进制比特流的方式传输文件的。
1.3 FTP文件的数据结构
- 文件结构:FTP的默认方式,默认文件是一个连续的字节流,文件内部没有表示结构的信息,纯粹看作连续的字节流
- 记录结构:只适用于文本文件,内部有记录文件结构的信息
- 页结构:FTP中文件的一个部分被称为页,文件被分为多个页,可以随机访问每个页的内容,传输的时候也可以分开传输,每个页都有页号来区别
1.4 文件的传输方式
- 流方式:默认的文件传输方式,以字节流的形式传输文件
- 块方式:对应记录结构的文件,每块前都包含子代码域和计数域,用来说明块的结束标志和字节数
- 压缩方式:主要用来对连续出现的相同字符进行压缩,很少用
1.5 FTP工作原理
FPT是基于客户/服务器模型的:
- FTP默认端口是21
- 客户在用户界面上输入的命令会被解释器解释为相关动作
- 传输文件的时候,服务器和客户端之间会建立一个新的通道专门用来传输文件,在建立新通道的时候可以有客户端发起,也可以有服务器发起,着对于这FTP的两种工作模式
- FTP有两种连接:控制连接负责FTP命令交互,数据连接负责文件的传输
1.6 FTP命令
FTP的动作就是由相关命令来控制的。
1.7 FTP 应答
什么是FTP应答
FTP中的应答是服务器通过控制连接发送给客户端的FTP应答,用来确保动作的一致性(保持同步),还可以获取服务器对用户刚才发生的命令进行反馈,以便客户端根据应答信息做进一步判定。
应答的格式为3位数字和一行文本提示信息,应答信息每行以回车+换行结束。如果需要产生一条多行的应答,第一行在 3 位数字应答代码之后包含一个连字符“-”,而不是空格符;最后一行包含相同的 3 位数字应答代码,后跟一个空格符
应答数字的含义
应答示例
#define FTP_DATACONN 150
#define FTP_NOOPOK 200
#define FTP_TYPEOK 200
#define FTP_PORTOK 200
#define FTP_EPRTOK 200
#define FTP_UMASKOK 200
#define FTP_CHMODOK 200
#define FTP_EPSVALLOK 200
#define FTP_STRUOK 200
#define FTP_CWDOK 250
#define FTP_RMDIROK 250
#define FTP_DELEOK 250
#define FTP_RENAMEOK 250
#define FTP_PWDOK 257
#define FTP_MKDIROK 257
#define FTP_GIVEPWORD 331
#define FTP_RESTOK 350
#define FTP_RNFROK 350
#define FTP_IDLE_TIMEOUT 421
#define FTP_DATA_TIMEOUT 421
#define FTP_TOO_MANY_USERS 421
#define FTP_BADOPTS 501
#define FTP_COMMANDNOTIMPL 502
#define FTP_NEEDUSER 503
#define FTP_NEEDRNFR 503
#define FTP_BADPBSZ 503
#define FTP_BADPROT 503
#define FTP_BADSTRU 504
#define FTP_BADMODE 504
#define FTP_BADAUTH 504
#define FTP_NOSUCHPROT 504
#define FTP_NEEDENCRYPT 522
#define FTP_EPSVBAD 522
#define FTP_DATATLSBAD 522c
#define FTP_LOGINERR 530
#define FTP_NOHANDLEPROT 536
#define FTP_FILEFAIL 550
#define FTP_NOPERM 550
#define FTP_UPLOADFAIL 553
1.8 FTP 两种工作模式
FTP的两种工作模式主要是针对数据连接来说的,在创建数据连接之前要选择工作模式,模式的选择是由客户端决定的。
控制连接的建立总是客户端向服务器发起的,而数据连接通道的建立分为两种情况:
- 服务器主动向客户端发起连接:主动模式PORT
- 服务器被动接受客户端连接:被动模式PASV
主动模式:
控制连接是三次握手建立的,通过控制连接客户端可以向服务器发送命令,服务器可以应答。
下面这种主动模式主要用到PORT、LIST命令:
客户端会向服务器发起一个PORT命令,服务器收到之后会应答(200表示准备就绪),接下来客户端发起一个LIST命令,即列出文件信息,这个列表的传输是在数据连接通道中完成的,所以服务器要根据PORT命令中的信息指定服务器要主动连接的端口,服务器通过20端口调用connect主动连接客户端。
所以PORT是在服务器登记客户端的信息,LIST命令之后就要主动建立一个数据连接通道了,一旦数据连接通道建立好之后就可以进行数据的传输。服务器向客户端发送150的应答表示可以进行数据传输,150和226应答之间就是数据的传输了。226指令表示数据传输完成,之后会将数据连接通道关闭。
关于PORT命令的信息:
16的端口号分为高八位p1和低八位p2进行传输。
客户端发送PORT命令的编程时候,相当于一个服务器模型,即要进行创建socket、绑定临时端口、监听socket、获取临时端口的信息以便于格式化发送。
被动模式:
被动模式是服务器接受客户端的连接,在接受PASV命令之后,服务器会告诉告知客户端被动模式的端口以便客户端主动连接服务器。
下面看一下PASV模式下双方交换的命令:
此时服务器上通过accept等待客户端的连接。
PS:当客户端主动关闭socket之后,服务器会通过read返回0来判断socket的关闭
1.9 NAT或防火墙对主动/被动模式的影响
为什么FTP数据连接通道会有主动模式与被动模式之分?是因为NAT或者防火墙对主被动模式有影响。
什么是NAT
NAT就是网络地址的转化,局域网中的主机要想进入互联网,就要有一个公网地址。因为私有的IP地址不可以和公有的IP地址进行通信,所以要通过NAT将局域网的私有IP转换为公网的IP地址。就是建立一个映射关系,由公网IP地址(端口)进行通信。
NAT默认维护由内到外的映射关系,从内向外的连接自然是没问题的。但是从外向内,如果连接的对象IP地址及端口是私有的,那么一般是不会建立成功的,除非用户手动建立映射。主动模式与被动模式的区别也是在这里,由NAT时从内向外没问题,但是从外向内就有问题了。
下面分析一下客户端、服务器分别处于NAT下的主动被动模式。
客户端处于NAT下的主动模式
要知道,主动模式中,客户端首先通过PORT向服务器发送其监听socket及端口号,客户端与服务器进行通信的IP地址及端口都是NAT映射的公网IP地址及端口,当服务器主动连接的时候,服务器是按照PORT中客户端私有IP地址及端口的,所以数据连接通道是无法建立的。
解决办法:
- 在NAT中手动配置映射关系,这种情况下NAT必须知道服务器主动连接的端口号才可以!!!这就是为什么服务器在主动模式下的端口号是固定的20
所以,当FTP服务器的控制连接可以建立,但是列表刷新不出来,就可能是客户端处于NAT下,且没有手动配置映射关系,导致服务器无法连接到PORT中客户端的端口。
客户端处于NAT下的被动模式
当客户端处于被动模式时,由客户端主动发起连接,这个时候是由NAT内部向外发起连接的,NAT内是维护一个由内向外的表的,所以连接是可以建立成功的。
服务器处于NAT下的主动模式
同理,当服务器处于主动模式下,相当于是从NAT内向外建立连接,自然是没有问题。
服务器处于NAT下的被动模式
同理,服务器处于被动模式下时,是客户端向服务器发送建立连接的请求,这个时候客户端知道私有地址以及固定的端口号21,而且服务器也早已经在NAT建立映射了,所以控制通道的建立是ok的。
被动模式下,服务器会告知客户端要连接的端口,但是这个端口并没有在NAT建立映射,所以当客户端的连接请求发送至NAT上时是无法建立连接的。