实现FTP Client功能
ubuntu搭建ftp服务器
1、选用vsftpd为我们的ftp服务器,端口号默认为21
安装:~$ sudo apt‐get install vsftpd
2、配置:~$ sudo gedit /etc/vsftpd.conf
3、 几个重要的参数:
1 anonymous_enable=NO 是否支持匿名访问
2
3 local_enable=YES 是否允许本地用户登录
4
5 write_enable=YES 是否给客户端写的权限 (默认只读)
4、几个重要的命令
1 ~$ sudo /etc/init.d/vsftpd restart 重启vsftp服务 (ubuntu 18)
2
3 ~$ ps ‐ef | grep ftp 查看ftp服务器是否启动
4
5 ~$ sudo netstat ‐utlpn | grep vsftp 查看vsftp状态及端口号
PS:如果想修改端口号(建议不要修改)
1、编辑/etc/vsftpd/vsftpd.conf 文件,在该配置文件中添加此行:listen_port=6666
2、编辑/etc/services 文件,将其中的 ftp 21/tcp 改为 ftp 21/tcp 改为 ftp 6666/tcp
QT实现ftp的客户端
通过该项目学会
QNetworkAccessManager上传和下载,对N多协议都支持;
QNetworkAccessManager 自己会新建线程 不用使用QThread
如果不需要遍历FtpServer目录可以直接使用QNetworkAccesssManager
- QUrl
- QNetworkAccessManager
- QNetworkReply
完整的ftp地址
完整代码
ftpAccessManager.h
1 #ifndef FTPACCESSMANAGER_H
2 #define FTPACCESSMANAGER_H
3
4 #include <QObject>
5 #include <QUrl>
6 #include <QNetworkAccessManager>
7 #include <QNetworkReply>
8 #include <QFile>
9 #include <QFileInfo>
10 #include <QDebug>
11 #include <QEvent>
12
13 class ftpAccessManager : public QObject
14 {
15 Q_OBJECT
16 public:
17 explicit ftpAccessManager(QObject *parent = nullptr);
18 virtual bool event(QEvent *event);
19
20 public:
21 // 设置端口
22 void setHostPortInfo(const QString &host, quint16 prot =21);
23 void setUserPwdInfo(const QString &userName, const QString &pwd);
24
25 // 下载路径
26 void putFileFromClent(const QString &fileName, const QString &path);
27 void getFileFromServer(const QString &fileName, const QString &path);
28
29 signals:
30 /* 以下信号上传给界面 */
31 void uploadProgressSignal(qint64, qint64);
32 void downloadProgressSignal(qint64, qint64);
33 void netErrorSignal(QNetworkReply::NetworkError);
34
35 private slots:
36 //上传时的槽
37 void uploadProgressSlot(qint64, qint64);
38 void uploadFinishedSlot();
39 void uploadErrorSlot(QNetworkReply::NetworkError);
40
41 //下载时的槽
42 void downloadProgressSlot(qint64, qint64);
43 void downloadFinishedSlot();
44 void downloadErrorSlot(QNetworkReply::NetworkError);
45
46 private:
47 QUrl murl;
48 QNetworkAccessManager mNetAccMgr;
49
50 QFile *putFileData = nullptr; //上传数据的文件指针
51 QFile *getFileData = nullptr;
52
53 QNetworkReply *putNetReply; //上传的网络应答 QNetworkRequest请求
54 QNetworkReply *getNetReply; //下载数据的网络
55
56
57
58 };
59
60 #endif // FTPACCESSMANAGER_H
ftpAccessManager.cpp
1 #include "ftpAccessManager.h"
2
3 ftpAccessManager::ftpAccessManager(QObject *parent)
4 : QObject{parent}
5 {
6 murl.setScheme("ftp"); // 设置协议
7 }
8
9 /*
10 * 设置FTP主机地址信息,包括Ip地址和端口号
11 */
12 void ftpAccessManager::setHostPortInfo(const QString &host, quint16 prot)
13 {
14 murl.setHost(host);
15 murl.setPort(prot);
16
17 }
18
19 /*
20 * 设置FTP用户密码信息
21 */
22 void ftpAccessManager::setUserPwdInfo(const QString &userName, const QString &pwd)
23 {
24 murl.setUserName(userName);
25 murl.setPassword(pwd);
26 }
27
28 /*
29 * 上传文件
30 * 参数1:本地文件(带路径) 参数2:服务器端文件(带路径) <服务器路径必须带上文件名,不然服务器不知道写什么样的文件>
31 */
32 void ftpAccessManager::putFileFromClent(const QString &clientFile, const QString &serverPath)
33 {
34 putFileData = new QFile(clientFile, this);
35 QString serverFileNamePath = serverPath + "/" +
36 QFileInfo(clientFile).fileName(); //路径+文件拼接,保证服务器端写入的文件和本地文件同名
37
38 //step1 :: setUrl
39 murl.setPath(serverFileNamePath);
40
41 //step2:打开文件 把文件读入到网络流发出去
42 if(putFileData->open(QIODevice::ReadOnly))
43 {
44 //step3:upload 上传
45 putNetReply = mNetAccMgr.put(QNetworkRequest(murl), putFileData);
46
47 //step4:关联信号与槽
48 connect(putNetReply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgressSlot(qint64, qint64)));
49 connect(putNetReply, SIGNAL(finished()), this, SLOT(uploadFinishedSlot()));
50 connect(putNetReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(uploadErrorSlot(QNetworkReply::NetworkError)));
51 }
52 else
53 {
54 delete putFileData;
55 putFileData = nullptr;
56 }
57 }
58
59 /*
60 * 下载文件
61 * 参数1:需要写入的本地文件(带路径 不带路径则为当前目录) 参数2:服务器端的路径
62 */
63 void ftpAccessManager::getFileFromServer(const QString &saveNameWithPath, const QString &downloadPath)
64 {
65 getFileData = new QFile(saveNameWithPath, this);
66
67 //step1 :: setUrl
68 murl.setPath(downloadPath);
69
70 if(getFileData->open(QIODevice::WriteOnly | QFile::Truncate))
71 {
72 getNetReply = mNetAccMgr.get(QNetworkRequest(murl));
73 //step4 :
74 connect(getNetReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgressSlot(qint64, qint64)));
75 connect(getNetReply, SIGNAL(finished()), this, SLOT(downloadFinishedSlot()));
76 connect(getNetReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadErrorSlot(QNetworkReply::NetworkError)));
77 }
78 else
79 {
80 delete getFileData;
81 getFileData = nullptr;
82 }
83 }
84
85
86 void ftpAccessManager::uploadProgressSlot(qint64 bytesSent, qint64 bytesTotal)
87 {
88 emit uploadProgressSignal(bytesSent, bytesTotal);
89 //qDebug() << "uploadProgressSlot" << bytesSent << bytesTotal;
90 }
91
92
93
94 void ftpAccessManager::uploadFinishedSlot()
95 {
96 qDebug() << "uploadFinishedSlot" ;
97
98 putNetReply->deleteLater();
99 delete putFileData;
100 putFileData = nullptr;
101 }
102
103 void ftpAccessManager::uploadErrorSlot(QNetworkReply::NetworkError errorCode)
104 {
105 putNetReply->deleteLater();
106 delete putFileData;
107 putFileData = nullptr;
108
109 switch (errorCode)
110 {
111 case QNetworkReply::HostNotFoundError :
112 qDebug() << "HostNotFoundError";
113 break;
114 case QNetworkReply::ConnectionRefusedError :
115 qDebug() << "ConnectionRefusedError";
116 break;
117 default:
118 qDebug() << "orther error" << errorCode;
119 break;
120 }
121
122 emit netErrorSignal(errorCode);
123 }
124
125 void ftpAccessManager::downloadProgressSlot(qint64 bytesSent, qint64 bytesTotal)
126 {
127
128 emit downloadProgressSignal(bytesSent, bytesTotal);
129 getFileData->write(getNetReply->readAll()); //写文件到磁盘
130 }
131
132
133 void ftpAccessManager::downloadFinishedSlot()
134 {
135 qDebug() << "downloadFinishedSlot";
136
137 getNetReply->deleteLater();
138 delete getFileData;
139 getFileData = nullptr;
140 }
141
142 void ftpAccessManager::downloadErrorSlot(QNetworkReply::NetworkError errorCode)
143 {
144 qDebug() << "downloadErrorSlot" << errorCode;
145
146 getNetReply->deleteLater();
147 delete getFileData;
148 getFileData = nullptr;
149
150 emit netErrorSignal(errorCode);
151 }
152
153 /* 演示deleteLater什么时候生效 */
154 bool ftpAccessManager::event(QEvent *event)
155 {
156 qDebug()<<"event" << event->isAccepted();
157 return true;
158 }
widget.h
1 #ifndef WIDGET_H
2 #define WIDGET_H
3
4 #include <QWidget>
5 #include <QMessageBox>
6 #include <QFileDialog>
7 #include "ftpAccessManager.h"
8
9
10 QT_BEGIN_NAMESPACE
11 namespace Ui { class Widget; }
12 QT_END_NAMESPACE
13
14 class Widget : public QWidget
15 {
16 Q_OBJECT
17
18 public:
19 Widget(QWidget *parent = nullptr);
20 ~Widget();
21
22 private slots:
23 void on_pushButtonDownload_clicked();
24
25 void on_pushButtonUpload_clicked();
26
27 void uploadProgressSlot(qint64, qint64);
28 void downloadProgressSlot(qint64, qint64);
29 void netErrorSlot(QNetworkReply::NetworkError);
30 private:
31 bool getHostInfoFromUi();
32
33 private:
34 Ui::Widget *ui;
35 ftpAccessManager mFtpAccMgr;
36 QString ftpServerHost;
37 qint16 ftpServerPort;
38 QString ftpServerUsr;
39 QString ftpServerPasswd;
40 };
41 #endif // WIDGET_H
widget.cpp
1 #include "widget.h"
2 #include "ui_widget.h"
3
4 Widget::Widget(QWidget *parent)
5 : QWidget(parent)
6 , ui(new Ui::Widget)
7 {
8 ui->setupUi(this);
9 connect(&mFtpAccMgr, SIGNAL(uploadProgressSignal(qint64,qint64)),
10 this, SLOT(uploadProgressSlot(qint64,qint64)));
11
12 connect(&mFtpAccMgr, SIGNAL(downloadProgressSignal(qint64,qint64)),
13 this, SLOT(downloadProgressSlot(qint64,qint64)));
14
15 connect(&mFtpAccMgr, SIGNAL(netErrorSignal(QNetworkReply::NetworkError)),
16 this, SLOT(netErrorSlot(QNetworkReply::NetworkError)));
17 }
18
19 Widget::~Widget()
20 {
21 delete ui;
22 }
23
24
25 bool Widget::getHostInfoFromUi()
26 {
27 ftpServerHost = ui->lineEditHostAddress->text();
28 ftpServerPort = ui->lineEditPort->text().toInt();
29 ftpServerUsr = ui->lineEditUsrName->text();
30 ftpServerPasswd = ui->lineEditPassWord->text();
31
32 if(ftpServerHost.isEmpty() || ftpServerUsr.isEmpty()
33 || ftpServerPasswd.isEmpty())
34 {
35 QMessageBox::warning(this, "Host Error", "Please input Host Info:Host Usr PWD");
36 return false;
37 }
38 return true;
39 }
40
41 void Widget::on_pushButtonUpload_clicked()
42 {
43 if(! getHostInfoFromUi())
44 return;
45
46 mFtpAccMgr.setHostPortInfo(ftpServerHost, ftpServerPort);
47 mFtpAccMgr.setUserPwdInfo(ftpServerUsr, ftpServerPasswd);
48
49 QString clientFile = QFileDialog::getOpenFileName(this,
50 QString::fromLocal8Bit("选择需要上传的文件"));
51 if(clientFile.isEmpty())
52 {
53 QMessageBox::warning(this, "upload error", "please select One file");
54 return;
55 }
56
57
58 QString serverPath = ui->lineEditUploadPath->text();
59 if(serverPath.isEmpty())
60 {
61 QMessageBox::warning(this, "upload error", "please select correct ftp path");
62 return;
63 }
64
65 mFtpAccMgr.putFileFromClent(clientFile, serverPath);
66 }
67
68
69 void Widget::on_pushButtonDownload_clicked()
70 {
71 if(! getHostInfoFromUi())
72 return;
73
74 QString downloadPath = ui->lineEditDownloadPath->text();
75
76 mFtpAccMgr.setHostPortInfo(ftpServerHost, ftpServerPort);
77 mFtpAccMgr.setUserPwdInfo(ftpServerUsr, ftpServerPasswd);
78
79 QString targetFileName = QFileInfo(downloadPath).fileName();
80
81 if(targetFileName.isEmpty())
82 return;
83
84 QString saveNameWithPath = QFileDialog::getSaveFileName(this,
85 QString::fromLocal8Bit("保存为..."),
86 targetFileName,
87 "");
88
89
90 mFtpAccMgr.getFileFromServer(saveNameWithPath, downloadPath);
91 }
92
93 void Widget::uploadProgressSlot(qint64 bytesReceived, qint64 bytesTotal)
94 {
95 // ui->progressBarUpload->setMaximum(bytesTotal);
96 // ui->progressBarUpload->setValue(bytesReceived);
97 //解决文件大小大于0x7fffffff情况 > int
98 qint32 fileSize = (qint32)(bytesReceived / (1024 * 1024)); //换成M单位
99 if(bytesReceived > 0 && fileSize == 0)
100 {
101 fileSize = 1;
102 }
103
104 qint32 totalSize = (qint32)(bytesTotal / (1024 * 1024));
105 if(bytesTotal > 0 && totalSize == 0)
106 {
107 totalSize = 1;
108 }
109
110 ui->progressBarUpload->setMaximum(totalSize); //这句话一定要写在setValue前面
111 ui->progressBarUpload->setValue(fileSize);
112 }
113
114 void Widget::downloadProgressSlot(qint64 bytesReceived, qint64 bytesTotal)
115 {
116 // ui->progressBarDownload->setMaximum(bytesTotal);
117 // ui->progressBarDownload->setValue(bytesReceived);
118 qint32 fileSize = (qint32)(bytesReceived / (1024 * 1024));
119 if(bytesReceived > 0 && fileSize == 0)
120 {
121 fileSize = 1;
122 }
123
124 qint32 totalSize = (qint32)(bytesTotal / (1024 * 1024));
125 if(bytesTotal > 0 && totalSize == 0)
126 {
127 totalSize = 1;
128 }
129
130 ui->progressBarDownload->setMaximum(totalSize);
131 ui->progressBarDownload->setValue(fileSize);
132 }
133
134 void Widget::netErrorSlot(QNetworkReply::NetworkError errorCode)
135 {
136 //显示在状态栏里
137 }