项目简介:
在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上时是无法建立连接的。

miniFTP项目实战一的更多相关文章

  1. 电子商务网站SQL注入项目实战一例

    故事A段:发现整站SQL对外输出: 有个朋友的网站,由于是外包项目,深圳某公司开发的,某天我帮他检测了一下网站相关情况. 我查看了页面源代码,发现了个惊人的事情,竟然整站打印SQL到Html里,着实吓 ...

  2. python3.6+selenium3.13 自动化测试项目实战一

    自己亲自写的第一个小项目,学了几天写出来的一个小模块,可能还不是很完美,但是还算可以了,初学者看看还是很有用的,代码注释不是很多,有问题可以加我QQ 281754043 一.项目介绍 目的: 测试某官 ...

  3. Kaggle项目实战一:Titanic: Machine Learning from Disaster

    项目地址 https://www.kaggle.com/c/titanic 项目介绍: 除了乘客的编号以外,还包括下表中10个字段,构成了数据的所有特征 Variable Definition Key ...

  4. docker自动化部署前端项目实战一

    docker自动化部署前端项目实战一 本文适用于个人项目,如博客.静态文档,不涉及后台数据交互,以部署文档为例. 思路 利用服务器node脚本,监听github仓库webhook push事件触发po ...

  5. Tensorflow项目实战一:MNIST手写数字识别

    此模型中,输入是28*28*1的图片,经过两个卷积层(卷积+池化)层之后,尺寸变为7*7*64,将最后一个卷积层展成一个以为向量,然后接两个全连接层,第一个全连接层加一个dropout,最后一个全连接 ...

  6. python 打飞机项目 (实战一)

    第一步定义 main 函数: # -*- coding=utf-8 -*- import pygame,time from Plane import Plane from pygame.locals ...

  7. miniFTP项目集合

    项目简介 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务进 ...

  8. miniFTP项目实战五

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

  9. miniFTP项目实战六

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

随机推荐

  1. idea中IDEA优化配置

    进入IDEA 设置.两种方法: 1,File  -> Settings 2,工具栏有个工具按钮点下(假如没工具栏,View -> 选下Toolbar) 进入设置页面,从上到下,主要是 外观 ...

  2. bugku Crypto 下半部分wp

    1. 百度托马斯这个人居然还发明了一种轮转的加密法,发现原理是,他将很多行乱序的26个字母,插到一根柱子上,参考糖葫芦的样子,可以旋转每一行,设置自己要发送的明文后,向对方发送乱码的一列,对方只要将这 ...

  3. 使用Hugo框架搭建博客的过程 - 页面模板

    前言 最初在制作友链界面时,没有学习Hugo框架,一头雾水.网上有关的教程甚少,只能去学一遍Hugo. 在学习Hugo的过程中,了解了列表模板,分类模板.开发了几个功能页面,如:留言板,友链,记忆分类 ...

  4. kali中设置共享文件夹

    1.在虚拟机设置共享目录 2.查看共享目录命令 root@kali:~# vmware-hgfsclient 3.新建文件夹 root@kali:~# mkdir /mnt/hgfs/ShareDir ...

  5. Django基础07篇 ORM操作

    1.新增(类似数据库操作的insert) # 新增 #方式一: models.Category.objects.create(name='MySQL') #方式二: c = models.Catego ...

  6. 【动画消消乐】HTML+CSS 自定义加载动画 061

    前言 Hello!小伙伴! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 自我介绍ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计算机专 ...

  7. 从代码生成说起,带你深入理解 mybatis generator 源码

    枯燥的任务 这一切都要从多年前说起. 那时候刚入职一家新公司,项目经理给我分配了一个比较简单的工作,为所有的数据库字段整理一张元数据表. 因为很多接手的项目文档都不全,所以需要统一整理一份基本的字典表 ...

  8. Redis学习——数据结构上

    一.常用的全局命令 1.查看所有的键: KEYS * KEYS pattern:查找所有符合给定模式 pattern 的 key . KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能 ...

  9. 在deeping上安装mariadb

    1,安装的官网参考:有安装的命令和指导https://downloads.mariadb.org/mariadb/repositories/#distro=Debian&distro_rele ...

  10. JavaScript学习笔记:你必须要懂的原生JS(一)

    1.原始类型有哪几种?null是对象吗?原始数据类型和复杂数据类型存储有什么区别? 原始类型有6种,分别是undefined,null,bool,string,number,symbol(ES6新增) ...