qt实现一个简单http服务器和客户端

一、功能简介

服务器:

登录功能、下载文件功能

客户端:

登录功能、下载文件功能、上传成绩功能
二、服务器代码

cpp 复制代码
//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
cpp 复制代码
//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;
}

三、客户端代码

cpp 复制代码
//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
cpp 复制代码
//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)

python 复制代码
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.结果

相关推荐
神秘的土鸡13 分钟前
Linux防火墙基础部分Firewalld防火墙(小白入门级别)
linux·运维·服务器·安全
逆枫゛1 小时前
Qt6相对Qt5的主要提升(AI总结)
开发语言·qt
yunbao00_2 小时前
网络基础(二)
运维·服务器·网络
风筝有风+2 小时前
学习应用层
服务器·网络·学习
程序员老舅2 小时前
Qt跨平台文件传输系统开发全解:TCP/IP协议+多线程架构
qt·网络协议·计算机毕设·文件传输·qt项目·qt项目实战·计算机毕设项目
碳烤小肥杨..2 小时前
单臂路由实验
服务器·网络·网络协议·网络安全·智能路由器
珹洺2 小时前
计算机网络:(三)计算机网络体系结构(附带图谱表格更好对比理解)
运维·服务器·网络·数据库·网络协议·计算机网络·网络安全
头发尚存的猿小二2 小时前
Linux--进程控制
linux·运维·服务器
耶耶耶耶耶~2 小时前
linux命令行工具进阶
linux·运维·服务器
不会敲代码的洋3 小时前
LVS的 NAT 模式实验
linux·运维·服务器·网络·lvs