一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

实现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 }

需要在pro文件中添加QT += network

posted on 2024-02-19 13:32  一杯清酒邀明月  阅读(403)  评论(0编辑  收藏  举报