【零基础学QT】【042】Qt网络框架

上传FTP文件


	//networkrequestcallback.h
		
	class NetworkRequestCallback : public QObject {
	    Q_OBJECT
	
	  public:
	    bool success = true;
	    void reset() {
	        success = true;
	    }
	
	  public slots:
	    void onFinish(QNetworkReply* repley) {
	        if (!success) return;
	        cout << "Request Done" << endl;
	    }
	    void onProgress(qint64 finish, qint64 total) {
	        if (!success) return;
	        cout << "Request Finished: " << finish << "/" << total << endl;
	    }
	    void onError(QNetworkReply::NetworkError error) {
	        success = false;
	        cout << "Request Error " << error << endl;
	    }
	};


	//main.cpp
	
    QApplication app(argc, argv);
    setlocale(LC_ALL, ".ACP");

    QNetworkAccessManager accessManager;
    accessManager.setNetworkAccessible(QNetworkAccessManager::Accessible);

    QUrl url("ftp://192.168.8.121/upload");
    url.setPort(8781);
    url.setUserName("root");
    url.setPassword("123456");
    url.setPath("a.json");  //如果要指定文件夹,将文件夹名拼接在url后面即可

    QFile file("C:/1.json");
    file.open(QFile::ReadOnly);

    //将本地的[1.json]文件上传到服务器上的[upload/a.json]位置
    QNetworkRequest request(url);
    QNetworkReply* reply = accessManager.put(request, &file);

    NetworkRequestCallback callback;
    callback.reset();
    QObject::connect(&accessManager, SIGNAL(finished(QNetworkReply*)), &callback, SLOT(onFinish(QNetworkReply*)));
    QObject::connect(reply, SIGNAL(uploadProgress(qint64, qint64)), &callback, SLOT(onProgress(qint64, qint64)));
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &callback, SLOT(onError(QNetworkReply::NetworkError)));

    return app.exec();

下载FTP文件


	//networkrequestcallback.h

	class NetworkRequestCallback : public QObject {
	    Q_OBJECT
	
	  private:
	    QNetworkReply* reply;
	
	  public:
	    bool success = true;
	    void reset(QNetworkReply* reply = nullptr) {
	        this->reply = reply;
	        success = true;
	    }
	
	  public slots:
	    void onFinish(QNetworkReply* repley) {
	        if (!success) return;
	        cout << "Request Done" << endl;
	    }
	    void onProgress(qint64 finish, qint64 total) {
	        if (!success) return;
	        cout << "Request Finished: " << finish << "/" << total << endl;
	    }
	    void onError(QNetworkReply::NetworkError error) {
	        success = false;
	        cout << "Request Error" << error << endl;
	    }
	    void onRead() {
	        QByteArray byteArray = reply->readAll();
	        QFile file("C:/1.json");
	        file.open(QFile::ReadWrite);
	        file.write(byteArray);
	        qdebug << byteArray << endl;
	        cout << "Read Byte Stream" << endl;
	    }
	};


	//main.cpp

    QApplication app(argc, argv);
    setlocale(LC_ALL, ".ACP");

    QNetworkAccessManager accessManager;
    accessManager.setNetworkAccessible(QNetworkAccessManager::Accessible);

    QUrl url("ftp://192.168.8.121/upload/a.json");
    url.setPort(8781);
    url.setUserName("root");
    url.setPassword("123456");

    //将服务器上的[upload/a.json]文件下载到本地[1.json]位置
    QNetworkRequest request(url);
    QNetworkReply* reply = accessManager.get(request);

    NetworkRequestCallback callback;
    callback.reset(reply);
    QObject::connect(&accessManager, SIGNAL(finished(QNetworkReply*)), &callback, SLOT(onFinish(QNetworkReply*)));
    QObject::connect(reply, SIGNAL(downloadProgress(qint64, qint64)), &callback, SLOT(onProgress(qint64, qint64)));
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &callback, SLOT(onError(QNetworkReply::NetworkError)));
    QObject::connect(reply, SIGNAL(readyRead()), &callback, SLOT(onRead()));

    return app.exec();

发送只有文本参数的Http请求
由于Get请求只有URL,比较简单,不再讲解,这里主要介绍Post请求方式


	//networkrequestcallback.h
	
	class NetworkRequestCallback : public QObject {
	    Q_OBJECT
	
	  private:
	    QNetworkReply* reply;
	
	  public:
	    bool success = true;
	    void reset(QNetworkReply* reply = nullptr) {
	        this->reply = reply;
	        success = true;
	    }
	
	  public slots:
	    void onError(QNetworkReply::NetworkError status) {
	        success = false;
	        cout << "Request Error " << status << endl;
	    }
	    void onRead() {
	        QNetworkReply::NetworkError status = reply->error();
	        QByteArray byteArray = reply->readAll();
	        qdebug << status << endl;
	        qdebug << byteArray << endl;
	        cout << "Read Byte Stream" << endl;
	    }
	};


	//main.cpp

    QApplication app(argc, argv);
    setlocale(LC_ALL, ".ACP");

    //网络请求处理器
    QNetworkAccessManager manager;

    //设置基本URL
    QUrl url("http://192.168.8.121:8001/animal/login");

    //设置URL额外参数
    QUrlQuery query;
    query.addQueryItem("username", "aodun");
    url.setQuery(query);

    //构建请求
    QNetworkRequest request(url);

    //设置请求头参数
    request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");

    //设置表单参数
    QByteArray formData;
    formData.append("&account=").append("aodun");
    formData.append("&password=").append("123456");

    //执行请求
    QNetworkReply* reply = manager.post(request, formData);

    //请求结果回调
    NetworkRequestCallback callback;
    callback.reset(reply);
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &callback, SLOT(onError(QNetworkReply::NetworkError)));
    QObject::connect(reply, SIGNAL(readyRead()), &callback, SLOT(onRead()));

    return app.exec();

发送带文件的Http请求
上面介绍的是URL_ENCODED_POST式的post请求,只有一块RequestBody
RequestBody用一段连续的键值对存放全部文本类型的表单参数
如果要上传文件,须使用MULTI_FORM_POST式的post请求
MULTI_FORM_POST将RequestBody分割为若干块,每个子块既可以存放文本,又可以存放文件
在Qt的网络框架中,QHttpMultiPart代表着顶级Body块,QHttpPart代表着分割后的子Body块


	//networkrequestcallback.h

	class NetworkRequestCallback : public QObject {
	    Q_OBJECT
	
	  private:
	    QNetworkReply* reply;
	
	  public:
	    bool success = true;
	    void reset(QNetworkReply* reply = nullptr) {
	        this->reply = reply;
	        success = true;
	    }
	
	  public slots:
	    void onError(QNetworkReply::NetworkError status) {
	        success = false;
	        qdebug << "Network Error: " << status << endl;
	    }
	    void onRead() {
	        qdebug << "Http Response Status: " << reply->error() << endl;
	        qdebug << "Http Response Body: " << reply->readAll() << endl;
	    }
	};


	//main.cpp

    QApplication app(argc, argv);
    setlocale(LC_ALL, ".ACP");

    //网络请求处理器
    QNetworkAccessManager manager;

    //设置基本URL
    QUrl url("http://192.168.8.121:8001/animal/file/upload");

    //构建请求
    QNetworkRequest request(url);

    //设置表单参数
    QHttpMultiPart* formData = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    //添加文本表单:folder=001
    QHttpPart textPart;
    textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"folder\"");
    textPart.setBody("001");
    formData->append(textPart);
    //添加文件表单:file=File
    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentTypeHeader, "image/png");
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"file\"; filename=\"1.png\"");
    QFile* file = new QFile("C:/1.png");
    file->open(QIODevice::ReadOnly);
    file->setParent(formData);  //绑定父级对象,Qt在父级对象回收时,会自动回收子级对象
    filePart.setBodyDevice(file);
    formData->append(filePart);

    //执行请求
    QNetworkReply* reply = manager.post(request, formData);

    //请求结果回调
    NetworkRequestCallback callback;
    callback.reset(reply);
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &callback, SLOT(onError(QNetworkReply::NetworkError)));
    QObject::connect(reply, SIGNAL(readyRead()), &callback, SLOT(onRead()));

    return app.exec();

下载Http文件
和普通请求一样,通过QNetworkReply.readAll(),就可以获取文件的全部字节,将字节写入文件即可完成下载


    void onRead() {
        qdebug << "Http Response Status: " << reply->error() << endl;
        qdebug << "Http Response Body: " << reply->readAll() << endl;
    }

发送RAW格式的Http请求
URL_ENCODED_POST式的post请求,RequestBody用一组键值对来存储若干文本参数
MULTI_FORM_POST式的post请求,RequestBody用若干子Body来分别存储文本或文件
RAW式的post请求,将整段文本直接放入RequestBody中,没有格式要求
这对于复杂类型的请求数据来说,比如JSON,XML,类对象等,非常方便,服务端可以将这些复杂文本数据直接转为对象使用
传统的Http编程中,Form格式比较常用,RAW格式的Http请求比较少见,但随着请求数据越来越复杂,后端数据解析越来越自动化,RAW格式是以后的一个趋势,因为它能力更强大,配合自动化框架使用也极方便


	//main.cpp

    QApplication app(argc, argv);
    setlocale(LC_ALL, ".ACP");

    //网络请求处理器
    QNetworkAccessManager manager;

    //设置基本URL
    QUrl url("http://192.168.8.121:8001/animal/test/v1");

    //构建请求
    QNetworkRequest request(url);
    request.setRawHeader("Content-Type", "application/json");

    //设置RAW格式请求体数据
    QJsonObject jsonObject;
    jsonObject.insert("account", "admin");
    jsonObject.insert("password", "123456");
    QByteArray rawData = QJsonDocument(jsonObject).toJson();

    //执行请求
    QNetworkReply* reply = manager.post(request, rawData);

    //请求结果回调
    NetworkRequestCallback callback;
    callback.reset(reply);
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &callback, SLOT(onError(QNetworkReply::NetworkError)));
    QObject::connect(reply, SIGNAL(readyRead()), &callback, SLOT(onRead()));

    return app.exec();

这里是一个简单的Json数据,虽然也可以用Form来实现,但是当数据存在多层嵌套时,就无法用Form来实现了,只能用Json、Xml或类对象来表示,然后放到RAW格式的RequestBody中来实现了
我们来看下服务端解析RAW数据有多简单,这里我们以Java的Spring后台为例


	//用来接收Json请求参数的类模型
	public class LoginRequest {
	
	    public String account;
	    public String password;
	}


	//自动将Json请求参数转为类对象
    @ResponseBody
    @RequestMapping(value = "/v1")
    public HttpResponseBody login(@RequestBody LoginRequest loginRequest) {
        System.out.println(loginRequest.account);
        return HttpResponseBody.success("ok");
    }

发送Binary格式的Http请求


	//main.cpp

    //网络请求处理器
    QNetworkAccessManager manager;

    //设置基本URL
    QUrl url("http://192.168.8.121:8001/animal/test/v1");

    //构建请求
    QNetworkRequest request(url);
    request.setRawHeader("Content-Type", "application/octet-stream");

    //设置Binary格式请求体数据
    QFile file("C:/animal-airport-v1.1.33.1181.apk");
    file.open(QFile::ReadWrite);
    QByteArray binData = file.readAll();

    //执行请求
    QNetworkReply* reply = manager.post(request, binData);	


	//server.java

    @ResponseBody
    @RequestMapping(value = "/v1")
    public HttpResponseBody saveBinaryData(@RequestBody byte[] body, HttpServletRequest request) {
        FileUtil.writeToFile("C:/1.apk", body);
        return HttpResponseBody.success("ok");
    }

使用TcpSocket


	int main(int argc, char* argv[]) {
	    QApplication app(argc, argv);
	    setlocale(LC_ALL, ".ACP");
	
	    QMainWindow* w = new QMainWindow();
	    w->setGeometry(100, 100, 300, 700);
	
	    QLineEdit* clientContentEdit = new QLineEdit(w);
	    clientContentEdit->setGeometry(0, 0, 300, 100);
	
	    QPushButton* clientSendButton = new QPushButton("Send Client Message", w);
	    clientSendButton->setGeometry(0, 100, 300, 50);
	
	    QLineEdit* serverContentEdit = new QLineEdit(w);
	    serverContentEdit->setGeometry(0, 150, 300, 100);
	
	    QPushButton* serverSendButton = new QPushButton("Send Server Message", w);
	    serverSendButton->setGeometry(0, 250, 300, 50);
	
	    QTextEdit* logPrintEdit = new QTextEdit(w);
	    logPrintEdit->setGeometry(0, 300, 300, 400);
	
	    w->show();
	
	    //创建Socket服务端
	    QTcpServer* socketServer = new QTcpServer();
	    socketServer->listen(QHostAddress::Any, 6666);
	
	    //监听客户端连接
	    QObject::connect(socketServer, &QTcpServer::newConnection, [=]() {
	        //获取连接的客户端
	        QTcpSocket* socket = socketServer->nextPendingConnection();
	        logPrintEdit->append("server: client connected");
	
	        //接收客户端消息
	        QObject::connect(socket, &QTcpSocket::readyRead, [=]() {
	            QByteArray message = socket->readAll();
	            logPrintEdit->append("server: receive message");
	            logPrintEdit->append(message);
	        });
	
	        //向客户端发送消息
	        QObject::connect(serverSendButton, &QPushButton::clicked, [=](bool) {
	            socket->write(serverContentEdit->text().toUtf8());
	        });
	    });
	
	    //创建Socket客户端
	    QTcpSocket* socketClient = new QTcpSocket();
	    socketClient->connectToHost("localhost", 6666);
	
	    //接收服务端消息
	    QObject::connect(socketClient, &QTcpSocket::readyRead, [=]() {
	        QByteArray message = socketClient->readAll();
	        logPrintEdit->append("client: receive message");
	        logPrintEdit->append(message);
	    });
	
	    //向服务端发送消息
	    QObject::connect(clientSendButton, &QPushButton::clicked, [=](bool) {
	        socketClient->write(clientContentEdit->text().toUtf8());
	    });
	
	    return app.exec();
	}

使用UdpSocket
UdpSocket发送的消息分为三类:单播,广播,组播
单播发送给指定设备,广播发送给全部设备,组播发送给一组设备
UdpSocket没有服务端和客户端之分,不用先建立连接,只要地址和端口,就可以收到彼此的消息
广播,组播,本质上也只是一个特殊的网络地址


	int main(int argc, char* argv[]) {
	    QApplication app(argc, argv);
	    setlocale(LC_ALL, ".ACP");
	
	    QTextEdit* consoleEdit = new QTextEdit();
	    consoleEdit->setGeometry(100, 100, 300, 400);
	    consoleEdit->show();
	
	    //创建UDP发送端
	    QUdpSocket* sender = new QUdpSocket();
	    sender->bind(QHostAddress::AnyIPv4, 5555, QUdpSocket::ShareAddress);
	    sender->joinMulticastGroup(QHostAddress("224.0.0.1"));
	    QObject::connect(sender, &QUdpSocket::readyRead, [=]() {
	        while (sender->hasPendingDatagrams()) {
	            //接收回复数据
	            QNetworkDatagram datagram = sender->receiveDatagram();
	            consoleEdit->append("sender: got message");
	            consoleEdit->append(datagram.data());
	        }
	    });
	
	    //创建UDP接收端
	    QUdpSocket* receiver = new QUdpSocket();
	    receiver->bind(QHostAddress::AnyIPv4, 6666, QUdpSocket::ShareAddress);
	    receiver->joinMulticastGroup(QHostAddress("224.0.0.1"));
	    QObject::connect(receiver, &QUdpSocket::readyRead, [=]() {
	        while (receiver->hasPendingDatagrams()) {
	            //接收数据
	            QNetworkDatagram datagram = receiver->receiveDatagram();
	            consoleEdit->append("receiver: got message");
	            consoleEdit->append(datagram.data());
	            //回复数据
	            QByteArray reply = "i got message";
	            receiver->writeDatagram(reply.data(), reply.size(), datagram.senderAddress(), datagram.senderPort());
	        }
	    });
	
	    //发送UDP单播消息
	    QByteArray d1 = "single broadcast";
	    sender->writeDatagram(d1.data(), d1.size(), QHostAddress::LocalHost, 6666);
	
	    //发送UDP广播消息
	    QByteArray d2 = "wide broadcast";
	    sender->writeDatagram(d2.data(), d2.size(), QHostAddress::Broadcast, 6666);
	
	    //发送UDP组播消息
	    QByteArray d3 = "group broadcast";
	    sender->writeDatagram(d3.data(), d3.size(), QHostAddress("224.0.0.1"), 6666);
	
	    return app.exec();
	}

使用Https
Qt默认是不支持Https的,需要手动安装OpenSSL支持库,可以通过以下链接下载
直接将对应版本的dll拷贝exe所在文件夹下面即可
https://download.csdn.net/download/u013718730/12066513

发布了442 篇原创文章 · 获赞 45 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/u013718730/article/details/103687213
今日推荐