• 使用Linux自带工具实现定时下载FTP文件(文末)

前言

自从Qt5删除了QFtp模块后,就没有了可方便使用的FTP类。根据官方的说法,是因为该模块实现质量不好被删除,而用Qt5的网络模块就可以轻松实现。对于初学者没了现成的工具就不知道该咋办了。本文从FTP协议开始讲起,先明白FTP协议是一个怎样的结构。然后讲解如何用代码去实现。

全文分两大部分,第一部分是FTP协议的讲解,第二部分是Qt5的代码实现。笔者会尽量用简洁明了的语句给列为讲清楚的,让我们开始吧~~

  1. FTP协议
  2. Qt5的代码实现

第一部分 FTP协议

什么是FTP协议?

就是传文件用的协议。整个过程就是先用TCP与服务器建立连接,然后发送命令,服务器执行并进行反馈。

FTP的两个端口

一般的客户端/服务器之间是开一个Socket端口,既传输命令又传输数据。而FTP的协议中说:我要开两个端口,一个传输命令,一个传输数据。

  • 传输命令端口(21)
  • 传输数据端口(20)

所以在编程的时候要创建两个QTcpSocket哦~

FTP的两种过程

分为被动模式和主动模式。这是从客户端的角度来说的。比如常见的被动模式意思就是服务器告诉你我们用哪个端口进行数据传输,我们(客户端)没有指定端口的权力,它(服务器)说用啥端口我们(客户端)就用啥端口。

而主动模式就是我们(客户端)自己定好用哪个端口,告诉了服务器,然后双方在这个端口下进行通信。

  • 被动模式(常用)

根据上文所述,既然都“被动”了,那我们客户端就等着服务器给我们分配端口号吧。

(1)首先我们任意打开一个端口N连接FTP服务器,并在Socket中写“PASV”命令。这里的N必须大于1024;

(2)然后服务器会返回个信息,类似“227 Entering Passive Mode(47,94,99,120,39,18)”这样。前四个是服务器IP地址,后两个是和分配的端口号相关的数。从这条信息我们就知道了服务器给我们分配的用于数据传输的端口号是:39*256+18;

(3)然后我们就打开第二个端口N+1和服务器的这个39*256+18端口进行连接,然后数据传输。

  • 主动模式

根据上文所述,既然都“主动”了,那我们客户端就自由分配进行数据传输的端口号吧。

(1)第一步还是任意打开两个端口N和N+1,先用N端口连接FTP服务器的21端口,同时第二个端口N+1进行监听。在第一个端口发送“port N+1”命令;

(2)这时服务器就会主动连接到我们的N+1端口上了。

FTP命令及响应码

FTP命令

命令字符串结尾要加'\n'

  • ABOR:中断数据连接程序
  • ACCT <account>:系统特权帐号
  • ALLO <bytes>:为服务器上的文件存储器分配字节
  • APPE <filename>:添加文件到服务器同名文件
  • CDUP <dir path>:改变服务器上的父目录
  • CWD <dir path>:改变服务器上的工作目录
  • DELE <filename>:删除服务器上的指定文件
  • HELP <command>:返回指定命令信息
  • LIST <name>:如果是文件名列出文件信息,如果是目录则列出文件列表
  • MODE <mode>:传输模式(S=流模式,B=块模式,C=压缩模式)
  • MKD <directory>:在服务器上建立指定目录
  • NLST <directory>:列出指定目录内容
  • NOOP:无动作,除了来自服务器上的承认
  • PASS <password>:系统登录密码
  • PASV:请求服务器等待数据连接
  • PORT <address>:IP 地址和两字节的端口 ID
  • PWD:显示当前工作目录
  • QUIT:从 FTP 服务器上退出登录
  • REIN:重新初始化登录状态连接
  • REST <offset>:由特定偏移量重启文件传递
  • RETR <filename>:从服务器上找回(复制)文件
  • RMD <directory>:在服务器上删除指定目录
  • RNFR <old path>:对旧路径重命名
  • RNTO <new path>:对新路径重命名
  • SITE <params>:由服务器提供的站点特殊参数
  • SMNT <pathname>:挂载指定文件结构
  • STAT <directory>:在当前程序或目录上返回信息
  • STOR <filename>:储存(复制)文件到服务器上
  • STOU <filename>:储存文件到服务器名称上
  • STRU <type>:数据结构(F=文件,R=记录,P=页面)
  • SYST:返回服务器使用的操作系统
  • TYPE <data type>:数据类型(A=ASCII,E=EBCDIC,I=binary)
  • USER <username>:系统登录的用户名

FTP响应码

  • 110:新文件指示器上的重启标记
  • 120:服务器准备就绪的时间(分钟数)
  • 125:打开数据连接,开始传输
  • 150:打开连接
  • 200:成功
  • 202:命令没有执行
  • 211:系统状态回复
  • 212:目录状态回复
  • 213:文件状态回复
  • 214:帮助信息回复
  • 215:系统类型回复
  • 220:服务就绪
  • 221:退出网络
  • 225:打开数据连接
  • 226:结束数据连接
  • 227:进入被动模式(IP 地址、ID 端口)
  • 230:登录因特网
  • 250:文件行为完成
  • 257:路径名建立
  • 331:要求密码
  • 332:要求帐号
  • 350:文件行为暂停
  • 421:服务关闭
  • 425:无法打开数据连接
  • 426:结束连接
  • 450:文件不可用
  • 451:遇到本地错误
  • 452:磁盘空间不足
  • 500:无效命令
  • 501:错误参数
  • 502:命令没有执行
  • 503:错误指令序列
  • 504:无效命令参数
  • 530:未登录网络
  • 532:存储文件需要帐号
  • 550:文件不可用
  • 551:不知道的页类型
  • 552:超过存储分配
  • 553:文件名不允许

第二部分 FTP的Qt5的代码实现

网络编程三步骤:Socket连接、Write/Read读写、Close关闭

  • 被动模式的代码实现

一般的服务器都是采用被动模式,所以先讲解这部分。

主界面

1/3 Socket连接

/* 构造Socket,并连接 */
socket = new QTcpSocket(this);
connect(socket,&QTcpSocket::connected,this,&MainWindow::slotConnected);
connect(socket,&QTcpSocket::readyRead,this,&MainWindow::dataReceived);
socket->connectToHost("47.94.99.120",21);

有两个槽,slotConnected()槽的作用是如果Socket和服务器建立连接,就在textEdit上显示“已建立Socket连接”的字样;dataeceived()槽的作用是显示服务器反馈回来的信息。

  • void slotConnected()槽
void MainWindow::slotConnected()
{ui->textEdit->append("已建立Socket连接");
}
  • void dataReceived()槽
void MainWindow::dataReceived()
{while (socket->bytesAvailable()){/* 读取Socket并存入datagram */QByteArray datagram = socket->readAll();/* 展示在textEdit */QString str = QString::fromLocal8Bit(datagram);ui->textEdit->append(str);}
}

看下效果:

通过连接,服务器反馈回“220 (vsFTPd 3.0.2)”的信息。由上文所述,220响应码的含义是“服务就绪”。那么接下来就是write/read过程了。

2/3 Write/Read读写

“发送命令”按钮的代码:

void MainWindow::on_pbSend_clicked()
{QByteArray command = ui->lineEdit->text().toLatin1();command += '\n';socket->write(command);
}

注意:命令结尾不要忘了加个'\n'回车符号。

发送 USER user_name 用户名

发送 PASS xxxxxxx 密码

发送 PASV 命令

到此为止,服务器给我们回复“227 Entering Passive Mode(47,94,99,120,39,16)”的响应码,这是要告诉我们“应该采用被动模式”,后面还附带了服务器IP地址,以及两个变量。通过计算得知,服务器给我们分配的数据传输端口号是:39*256+16=10000。

接下来就是再构造一个Socket,端口号为10000,去连接服务器的20端口号(传输数据用)。然后各种命令,接受的文件也用Socket的read()等函数去接受,然后QFile各种存文件操作等等等等。


接下来的步骤就不写了,FTP协议属于应用层的部分,具体如何按照这个标准去组织语言就是列位发挥的部分了。

刚开始我写FTP协议的时候摸不着头脑,也不懂HTTP协议、FTP协议等内容,后来经过摸索才知道:哦,这就是应用层的东西。人家都已经告诉你如何去实现FTP的过程了,我们就照着这个过程写程序就是咯。

所以整个过程还是很简单的,就是用Socket去你来我往的交流而已,没有涉及多么高大上的东西。FTP协议很简单吧~


使用Linux自带工具实现定时下载FTP文件(4月8日新增)

总共分两步骤:编写下载脚本、添加定时任务。

编写下载脚本

#!/bin/bashftp -n << EOF
open xxx.xxx.xxx.xxx       #FTP服务器地址
user username password     #用户名、密码
binary
lcd /home/psx/data         #设置文件保存位置
prompt
mget *
close
byeEOF

其中,prompt意思是关闭交互。

添加定时任务(每分钟执行一次)

打开终端输入:

crontab -e

编写内容:

*/1 * * * * /bin/bash /home/psx/download_ftp

download_ftp是我自己写的脚本,你改成自己的脚本路径。*号和空格不能少。然后按ESC,按shift+:,输入wq保存退出即可立即生效。

关于crontab参数含义可以网上搜索下看看,非常简单。

明明白白用Qt5.10编写FTP客户端相关推荐

  1. 18. 编写FTP客户端程序

    在实际应用中可能经常访问FTP服务器来上传或下载文件,Python也可以替我们做这些. [示例 1]下面请看一个例子(ftpclient). 运行的结果如下: FTP客户端程序的编写还可以参照官方文档 ...

  2. python编写ftp客户端_用Python写FTP客户端程序

    0 前言: ftp客户端相信大家都用过,那么我们为什么还要用Python写ftp客户端呢? 我想有两个原因: 一是写出更好的ftp客户端应用程序,方便大家使用: 二是定制一些特殊服务,例如每天定时下载 ...

  3. python ftplib_python:使用ftplib编写FTP客户端

    Python中的ftplib模块 Python中默认安装的ftplib模块定义了FTP类,其中函数有限,可用来实现简单的ftp客户端,用于上传或下载文件 FTP的工作流程及基本操作可参考协议RFC95 ...

  4. python编写ftp客户端_python实现ftp客户端示例分享

    代码如下: #!/usr/bin/python #coding:utf-8 #write:JACK #info:ftp example import ftplib, socket, os from t ...

  5. Qt5.10编写俄罗斯方块

    一.先看效果图 二.主要的设计思路: 1.采用Qt的QGraphicsScene.QGraphicsScene.QGraphicsItem实现界面的绘制: 2.对每一种类型的方块单独设计一个类,所有类 ...

  6. paho | 支持10种语言编写mqtt客户端,总有一款适合你!

    1. 轻量级物联网协议 - MQTT MQTT全称 Message Queuing Telemetry Transport,即消息队列遥测传输协议,是一种基于发布/订阅(publish/subscri ...

  7. C#毕业设计——基于C#+asp.net+FTP的FTP客户端设计与实现(毕业论文+程序源码)——FTP客户端

    基于C#+asp.net+FTP的FTP客户端设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于C#+asp.net+FTP的FTP客户端设计与实现,文章末尾附有本毕业设计的论文和源码下载地 ...

  8. FTP客户端设计与实现

    互联网的一大特点是实现信息共享,文件传输是信息共享的十分重要的内容之一.随之出现了许多FTP服务器来共享一些信息资源,编写一个操作简单,方便的FTP客户端来下载这些资源受到了人们的极大欢迎. FTP客 ...

  9. 基于java的ftp客户端_基于Java的FTP客户端软件的设计

    基于的FTP客户端软件的设计(含选题审批表,任务书,开题报告,中期检查表,毕业论文8600字,答辩记录) 摘 要:FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中 ...

最新文章

  1. JavaScript字符串
  2. c efcore.mysql_EF Core在mysql中调用存储过程
  3. linux 驱动开发 --- 字符设备与混杂设备区别
  4. 31.错误处理.rs
  5. 字符串匹配算法(二):BM(BoyerMoore)算法、坏字符规则,好后缀规则
  6. 人民的名义中,为什么蔡成功的贷款这么难?
  7. MyEclipse10 Tomcat7 JDK1.7 配置
  8. 脉冲宽度调制pdm_PWM (脉冲宽度调制)原理与实现
  9. Win7系统隐藏文件恢复的方法
  10. 自己做站点(一) 从头至尾实现一个企业站的速成
  11. 看看在职场里是怎么混社会的……
  12. Not showing null elements
  13. 无处不在的健康关爱 东软发布健康云战略
  14. OSX: 使用命令行对FileVault2分区恢复
  15. 计算机基础实训项目二 Word 综合应用,计算机应用基础-实训项目二 Word 综合应用[优质文档]...
  16. 物联网卡怎么激活 如何计费
  17. 探访广东第二鬼城,一座长在石油上的城市
  18. opencv 锐化 java_Java Opencv 实现锐化
  19. SSM三大框架整合(Spring+SpringMVC+MyBatis)
  20. Android Realm数据库完美解析

热门文章

  1. 区块链带来的技术创新和变革
  2. iOS(Swift)学习笔记之SwiftyJSON的使用
  3. MySQL存储过程示例
  4. Kubernetes--k8s---进阶--AWS托管式容器服务EKS--EKS全面介绍和安装使用
  5. ProcessMonitor文件以及注册表监视器的使用
  6. 【51单片机】连接蓝牙模块(AT模式、解决返回乱码)
  7. 图片怎么压缩到100k以下?
  8. 004-PBR历史和概念
  9. 分享一些实用的软件工具
  10. oc和java的优点缺点_oc语言的优点和缺点