一、功能简介
服务器:
登录功能、下载文件功能
客户端:
登录功能、下载文件功能、上传成绩功能
二、服务器代码
//HttpServer.h
#ifndef HTTPSERVER_H
#define HTTPSERVER_H
#include <QMainWindow>
#include <QTcpSocket>
#include <QTcpServer>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include <QString>
#include <QCoreApplication>
#include <QDir>
class Server:public QTcpServer
{
//http服务器类
Q_OBJECT
public:
Server(QObject *parent = nullptr) : QTcpServer(parent) {}
signals:
//信号函数
//自定义信号函数,发送信号,将信息显示在界面类上的textedit中
void login_success(QString str);
void login_faild(QString str);
void download_success(QString str);
void download_faild(QString str);
void upload_success(QString str);
protected:
void incomingConnection(qintptr socketDescriptor) override {
QTcpSocket *socket = new QTcpSocket(this);
socket->setSocketDescriptor(socketDescriptor);
connect(socket, &QTcpSocket::readyRead, this, [this, socket]() {
handleRequest(socket);
});
}
private:
void handleRequest(QTcpSocket *socket)
{
QString request = socket->readAll();
QStringList lines = request.split("\r\n");
QString requestLine = lines[0];
QStringList requestParts = requestLine.split(" ");
QString method = requestParts[0];
QString path = requestParts[1];
if (method == "POST" && path == "/login") {
handleLogin(socket, request);
} else if (method == "GET" && path == "/download") {
handleDownload(socket);
} else if (method == "POST" && path == "/upload") {
handleUpload(socket, request);
} else {
sendResponse(socket, 404, "Not Found");
}
}
void handleLogin(QTcpSocket *socket, const QString &request)
{
// 解析请求体
QString body = request.split("\r\n\r\n").last();
QJsonDocument doc = QJsonDocument::fromJson(body.toUtf8());
QJsonObject json = doc.object();
QString username = json["username"].toString();
QString password = json["password"].toString();
// 简单验证
if (username == "admin" && password == "123456") {
sendResponse(socket, 200, "Login Success");
emit login_success(username+":"+"Login Success!");
//ui->textEdit->append(username+":"+"Login Success!");
} else {
sendResponse(socket, 401, "Login Failed");
emit login_faild(username+":"+"Login Failed!");
//ui->textEdit->append(username+":"+"Login Failed!");
}
}
void handleDownload(QTcpSocket *socket)
{
// 获取应用程序的当前目录
QString appDir = QCoreApplication::applicationDirPath();
// 构建文件的完整路径
QString filePath = QDir(appDir).filePath("test.txt");
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {
QByteArray data = file.readAll();
sendResponse(socket, 200, data);
file.close();
emit upload_success("download Success!");
} else {
emit upload_success("download Failed!");
sendResponse(socket, 404, "File Not Found");
}
}
void handleUpload(QTcpSocket *socket, const QString &request)
{
QString body = request.split("\r\n\r\n").last();
QJsonDocument doc = QJsonDocument::fromJson(body.toUtf8());
QJsonObject json = doc.object();
QString chinese = json["chinese"].toString();
QString math = json["math"].toString();
QString english = json["english"].toString();
// 简单处理,打印上传的数据
emit upload_success("语文:"+chinese+";"+"数学:"+math+";"+"英语:"+english);
qDebug() << "语文:" << chinese << "数学:" << math << "英语:" << english;
sendResponse(socket, 200, "Upload Success");
}
void sendResponse(QTcpSocket *socket, int statusCode, const QByteArray &body)
{
QString response = QString("HTTP/1.1 %1 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %2\r\n"
"\r\n"
"%3")
.arg(statusCode)
.arg(body.size())
.arg(QString(body));
socket->write(response.toUtf8());
socket->disconnectFromHost();
}
};
QT_BEGIN_NAMESPACE
namespace Ui {
class HttpServer;
}
QT_END_NAMESPACE
class HttpServer : public QMainWindow
{
//http服务器界面类
Q_OBJECT
public:
HttpServer(QWidget *parent = nullptr);
~HttpServer();
private:
Ui::HttpServer *ui;
Server* m_server;
};
#endif // HTTPSERVER_H
//HttpServer.cpp
#include "httpserver.h"
#include "ui_httpserver.h"
HttpServer::HttpServer(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::HttpServer)
{
ui->setupUi(this);
m_server= new Server();
m_server->listen(QHostAddress::Any,8080);
connect(m_server,&Server::login_success,this,[=](QString str)
{
ui->textEdit->append(str);
});
connect(m_server,&Server::login_faild,this,[=](QString str)
{
ui->textEdit->append(str);
});
connect(m_server,&Server::download_success,this,[=](QString str)
{
ui->textEdit->append(str);
});
connect(m_server,&Server::download_faild,this,[=](QString str)
{
ui->textEdit->append(str);
});
connect(m_server,&Server::upload_success,this,[=](QString str)
{
ui->textEdit->append(str);
});
}
HttpServer::~HttpServer()
{
delete ui;
}
三、客户端代码
//HttpClient.h
#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H
#include <QMainWindow>
#include<QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include <QDebug>
#include <QPushButton>
QT_BEGIN_NAMESPACE
namespace Ui {
class HttpClient;
}
QT_END_NAMESPACE
class HttpClient : public QMainWindow
{
Q_OBJECT
public:
HttpClient(QWidget *parent = nullptr);
~HttpClient();
private:
Ui::HttpClient *ui;
QNetworkAccessManager *manager;
private slots:
void login( );
void downloadFile( );
void uploadScore( );
};
#endif // HTTPCLIENT_H
//HttpClient.cpp
#include "httpclient.h"
#include "ui_httpclient.h"
HttpClient::HttpClient(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::HttpClient)
{
ui->setupUi(this);
manager=new QNetworkAccessManager;
connect(ui->pb_login,&QPushButton::clicked,this,&HttpClient::login);
connect(ui->pu_down,&QPushButton::clicked,this,&HttpClient::downloadFile);
connect(ui->pb_upload,&QPushButton::clicked,this,&HttpClient::uploadScore);
}
void HttpClient::login()
{
QUrl url("http://127.0.0.1:8080/login");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QJsonObject json;
json["username"] = ui->li_name->text();//admin
json["password"] = ui->li_pswd->text();//123456
QNetworkReply *reply = manager->post(request, QJsonDocument(json).toJson());
QObject::connect(reply, &QNetworkReply::finished, [reply]() {
if (reply->error() == QNetworkReply::NoError) {
qDebug() << "Login Response:" << reply->readAll();
} else {
qDebug() << "Login Error:" << reply->errorString();
}
reply->deleteLater();
});
}
void HttpClient::downloadFile()
{
QUrl url("http://127.0.0.1:8080/download");
QNetworkRequest request(url);
QNetworkReply *reply = manager->get(request);
QObject::connect(reply, &QNetworkReply::finished, [reply]() {
if (reply->error() == QNetworkReply::NoError) {
QByteArray data = reply->readAll();
QFile file("D:\\Project\\qtcreator\\HttpClient\\downloaded.txt");
if (file.open(QIODevice::WriteOnly)) {
file.write(data);
file.close();
qDebug() << "File downloaded successfully!";
}
} else {
qDebug() << "Download Error:" << reply->errorString();
}
reply->deleteLater();
});
}
void HttpClient::uploadScore()
{
QUrl url("http://127.0.0.1:8080/upload");
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QJsonObject json;
json["chinese"] = ui->li_chinese->text();
json["math"] =ui->li_math->text();
json["english"] = ui->li_english->text();
QNetworkReply *reply = manager->post(request, QJsonDocument(json).toJson());
QObject::connect(reply, &QNetworkReply::finished, [reply]() {
if (reply->error() == QNetworkReply::NoError) {
qDebug() << "Upload Response:" << reply->readAll();
} else {
qDebug() << "Upload Error:" << reply->errorString();
}
reply->deleteLater();
});
}
HttpClient::~HttpClient()
{
delete ui;
}
四、其他设置
1.不管是服务器还是客户端,都要在.pro文件中添加 network
QT += core gui network
2.保证在httpserver.exe目录下有text.txt文件
五、测试
分别运行服务器与客户端程序
1.登录功能
客户端输入用户名与密码,点击登录
2.下载功能
3.上传功能
六、追加python测试
1.下载库(pip install requests)
import requests
# 服务器地址和端口
SERVER_URL = "http://localhost:8080"
def test_login():
"""
测试用户登录接口
"""
url = f"{SERVER_URL}/login"
data = {
"username": "admin",
"password": "123456"
}
response = requests.post(url, json=data)
# 验证响应
if response.status_code == 200:
print("Login Test: PASSED")
else:
print(f"Login Test: FAILED (Status Code: {response.status_code}, Response: {response.text})")
def test_download():
"""
测试文件下载接口
"""
url = f"{SERVER_URL}/download"
response = requests.get(url)
# 验证响应
if response.status_code == 200:
print("Download Test: PASSED")
print("File Content:")
print(response.text) # 打印文件内容
else:
print(f"Download Test: FAILED (Status Code: {response.status_code}, Response: {response.text})")
def test_upload():
"""
测试成绩上传接口
"""
url = f"{SERVER_URL}/upload"
data = {
"chinese": "80",
"math": "90",
"english": "79"
}
response = requests.post(url, json=data)
# 验证响应
if response.status_code == 200:
print("Upload Test: PASSED")
else:
print(f"Upload Test: FAILED (Status Code: {response.status_code}, Response: {response.text})")
def run_tests():
"""
运行所有测试
"""
print("Running Tests...")
test_login()
test_download()
test_upload()
print("All Tests Completed.")
if __name__ == "__main__":
run_tests()
3.结果