Qt 网络:包含Udp、Tcp、Http三种协议的客户端实践手册

文章目录

  • [4. Qt 网络](#4. Qt 网络)
    • [4.1 UDP Socket](#4.1 UDP Socket)
      • [4.1.1 API](#4.1.1 API)
      • [4.1.2 回显服务器(UDP)](#4.1.2 回显服务器(UDP))
      • [4.1.3 回显客户端(UDP)](#4.1.3 回显客户端(UDP))
    • [4.2 TCP Socket](#4.2 TCP Socket)
      • [4.2.1 API](#4.2.1 API)
      • [4.2.2 回显服务器(TCP)](#4.2.2 回显服务器(TCP))
      • [4.2.3 回显客户端(TCP)](#4.2.3 回显客户端(TCP))
    • [4.3 HTTP Client](#4.3 HTTP Client)
      • [4.3.1 核心 API](#4.3.1 核心 API)
      • [4.3.2 HTTP GET 请求](#4.3.2 HTTP GET 请求)

4. Qt 网络

Qt Network 是 Qt 框架中专门用于跨平台网络编程的核心模块,复杂的底层网络协议(如 TCP/UDP/HTTP)和操作系统原生的 socket API 封装成了易用的 C++ 类。

使用 Qt 网络模块时,需要在项目的 .pro 文件中添加一行配置,确保链接到网络库:

plaintext 复制代码
QT += network

4.1 UDP Socket

  • QUdpSocket:UDP 套接字,负责绑定端口、收发数据报。
  • QNetworkDatagram:UDP 数据报,封装数据、目标地址、端口等。

4.1.1 API

QUdpSocket 核心方法/信号

名称 说明
bind(const QHostAddress& addr, quint16 port) 绑定地址和端口
receiveDatagram() 读取一个 UDP 数据报,返回 QNetworkDatagram
writeDatagram(const QNetworkDatagram& datagram) 发送 UDP 数据报
readyRead 收到数据时触发

QNetworkDatagram 核心方法

名称 说明
QNetworkDatagram(const QByteArray& data, const QHostAddress& addr, quint16 port) 构造数据报(数据、目标地址、端口)
data() 获取数据报内容(返回 QByteArray)
senderAddress() 获取发送方 IP 地址
senderPort() 获取发送方端口号

4.1.2 回显服务器(UDP)

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setWindowTitle("服务端");
    //创建套接字
    socket=new QUdpSocket(this);
    //绑定信号槽
    connect(socket,&QUdpSocket::readyRead,this,&Widget::handlerudp);
    //绑定端口号
    if(socket->bind(QHostAddress::Any,8080)==false)
    {
        QMessageBox::critical(this,"服务器启动错误",socket->errorString());
    }
}

Widget::~Widget()
{
    delete ui;
}

void Widget::handlerudp()
{
    auto handlerresponse = [&](const QString& req){
        return "resp:"+req;
    };
    //1.读取请求
    const QNetworkDatagram& requestDatagarm=socket->receiveDatagram();
    QString request=requestDatagarm.data();
    //2.处理请求
    const QString& response= handlerresponse(request);
    //3.发回请求
    socket->writeDatagram(QNetworkDatagram(response.toUtf8(),requestDatagarm.senderAddress(),requestDatagarm.senderPort()));

    ui->listWidget->addItem("[" + requestDatagarm.senderAddress().toString() + ":"
                                    + QString::number(requestDatagarm.senderPort())
                                     + "] req: " + request + ", resp: " + response);
}

4.1.3 回显客户端(UDP)

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    socket=new QUdpSocket(this);

    this->setWindowTitle("客户端");
    ui->pushButton->setShortcut(QKeySequence(Qt::Key_Return | Qt::Key_Enter));


    connect(ui->lineEdit, &QLineEdit::returnPressed, ui->pushButton, &QPushButton::click);
    connect(socket, &QUdpSocket::readyRead, this, &Widget::handlerres);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_clicked()
{
    QString str=ui->lineEdit->text();
    ui->lineEdit->setText("");

    ui->listWidget->addItem("发送: "+str);
    //构建发送请求
    QNetworkDatagram requestDatagram(str.toUtf8(),QHostAddress("127.0.0.1"),8080);
    socket->writeDatagram(requestDatagram);
}

void Widget::handlerres()
{
    const QNetworkDatagram& recieveDatagarm=socket->receiveDatagram();
    QString request=recieveDatagarm.data();

    ui->listWidget->addItem("收到: "+ request);
}

4.2 TCP Socket

  • QTcpServer:服务器端,负责监听端口、接收客户端连接。
  • QTcpSocket:客户端/服务器端通信套接字,负责数据读写。

4.2.1 API

QTcpServer 核心方法/信号

名称 说明 对标原生 API
listen(const QHostAddress& addr, quint16 port) 绑定地址端口并开始监听 bind + listen
nextPendingConnection() 获取已建立的客户端连接(返回 QTcpSocket*) accept
newConnection 有新客户端连接时触发 -

QTcpSocket 核心方法/信号

名称 说明 对标原生 API
readAll() 读取接收缓冲区所有数据(返回 QByteArray) read
write(const QByteArray& data) 写入数据到套接字 write
deleteLater() 标记对象待销毁,下一个事件循环释放 -
readyRead 收到数据时触发 -
disconnected 连接断开时触发 -
connectToHost(const QString& addr, quint16 port) 客户端连接服务器 connect

4.2.2 回显服务器(TCP)

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setWindowTitle("服务端");

    tcpserver();
}

void Widget::tcpserver()
{
    //创建套接字
    tcpsocket=new QTcpServer(this);
    //绑定信号槽
    connect(tcpsocket,&QTcpServer::newConnection,this,&Widget::handlertcp);
    //绑定端口号
    if(tcpsocket->listen(QHostAddress::Any,8080)==false)
    {
        QMessageBox::critical(this,"服务器启动错误",tcpsocket->errorString());
    }

}


Widget::~Widget()
{
    delete ui;
}

void Widget::handlertcp()
{
    //获得socket对象,通过这个与客户端进行通信
    QTcpSocket* clientSocket = tcpsocket->nextPendingConnection();
    //绑定信号槽
    connect(clientSocket,&QTcpSocket::readyRead,this,[=](){
        auto handlerresponse = [&](const QString& req){
            return "resp:"+req;
        };
        //1.读取请求
        QString request=clientSocket->readAll();
        //2.处理请求
        const QString& response= handlerresponse(request);
        //3.发回请求
        clientSocket->write(response.toUtf8());

        ui->listWidget->addItem("[" + clientSocket->peerAddress().toString() + ":"
                                        + QString::number(clientSocket->peerPort())
                                + "] req: " + request + ", resp: " + response);
    });

    //处理断开连接
    connect(clientSocket,&QTcpSocket::disconnected,this,[=](){
        ui->listWidget->addItem("[" + clientSocket->peerAddress().toString() + ":"
                                        + QString::number(clientSocket->peerPort())
                                + "] 连接断开");

        clientSocket->deleteLater();//将缓冲区内存读取完毕再销毁,better than 直接delete
    });
}

4.2.3 回显客户端(TCP)

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setWindowTitle("客户端");
    ui->pushButton->setShortcut(QKeySequence(Qt::Key_Return | Qt::Key_Enter));

    connect(ui->lineEdit, &QLineEdit::returnPressed, ui->pushButton, &QPushButton::click);
    //handlerudpres();
    handlertcpres();
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_clicked()
{
    auto sendudp=[=](const QString& str){
        QNetworkDatagram requestDatagram(str.toUtf8(),QHostAddress("127.0.0.1"),8080);
        udpsocket->writeDatagram(requestDatagram);
    };

    auto sendtcp=[=](const QString& str){
        tcpsocket->write(str.toUtf8());
    };

    QString str=ui->lineEdit->text();
    ui->lineEdit->setText("");

    ui->listWidget->addItem("发送: "+str);
    //构建发送请求
    sendtcp(str);

}

void Widget::handlertcpres()
{
    tcpsocket=new QTcpSocket(this);
    //与服务器建立连接(非阻塞)
    tcpsocket->connectToHost("127.0.0.1",8080);
    //判断建立结果
    if( tcpsocket->waitForConnected()==false)
    {
        QMessageBox::critical(this,"服务器启动错误",tcpsocket->errorString());
    }

    connect(tcpsocket, &QTcpSocket::readyRead, this, [=](){

        QString request=tcpsocket->readAll();

        ui->listWidget->addItem("收到: "+ request);
    });

}

4.3 HTTP Client

Qt 通过 QNetworkAccessManager、QNetworkRequest、QNetworkReply 类实现 HTTP 通信,支持 GET、POST 等请求。由于 Qt 常作为客户端/前端访问服务器,所以

4.3.1 核心 API

QNetworkAccessManager 核心方法

方法 说明
get(const QNetworkRequest& request) 发起 HTTP GET 请求,返回 QNetworkReply*
post(const QNetworkRequest& request, const QByteArray& data) 发起 HTTP POST 请求,返回 QNetworkReply*

QNetworkRequest 核心方法

方法 说明
QNetworkRequest(const QUrl& url) 通过 URL 构造请求
setHeader(QNetworkRequest::KnownHeaders header, const QVariant& value) 设置请求头(如 Content-Type、User-Agent)

QNetworkRequest::KnownHeaders 常用取值

取值 说明
ContentTypeHeader 请求体类型(如 application/json)
ContentLengthHeader 请求体长度
CookieHeader Cookie 信息
UserAgentHeader 客户端标识(User-Agent)

QNetworkReply 核心方法/信号

方法/信号 说明
error() 获取请求错误状态(QNetworkReply::NoError 为成功)
errorString() 获取错误描述
readAll() 读取响应体数据
header(QNetworkRequest::KnownHeaders header) 读取响应头
finished() 请求完成(成功/失败)时触发

4.3.2 HTTP GET 请求

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    manager=new QNetworkAccessManager(this);

}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_clicked()
{
    QString url=ui->lineEdit->text();
    //构造http请求
    QNetworkRequest request(url);
    //发送请求
    QNetworkReply* response=manager->get(request);
    //信号槽处理
    connect(response,&QNetworkReply::finished,this,[=](){
        //判断是否出错
        if(response->error()==QNetworkReply::NoError)
        {
            QString html=response->readAll();//一般访问到的都是html
            ui->listWidget->addItem(html);
        }
        else
        {
            QMessageBox::critical(this,"服务器启动错误",response->errorString());
        }

        response->deleteLater();
    });
}
相关推荐
jojo_zjx2 小时前
GESP 23年6月2级 找素数
c++
We་ct2 小时前
LeetCode 238. 除了自身以外数组的乘积|最优解详解(O(n)时间+O(1)空间)
前端·算法·leetcode·typescript
kimicsdn2 小时前
opentelemetry-demo currency cpp 项目编译流程分享
c++·cmake·libprotobuf-dev
闻缺陷则喜何志丹2 小时前
【动态规划】P9980 [USACO23DEC] Flight Routes G|普及+
c++·算法·动态规划·洛谷
AC赳赳老秦2 小时前
低代码开发中的高效调试:基于 DeepSeek 的报错日志解析与自动修复方案生成
前端·javascript·低代码·postgresql·数据库架构·easyui·deepseek
乐迁~2 小时前
前端PDF导出完全指南:JSPDF与HTML2Canvas深度解析与实战(上)
前端·pdf
橘颂TA2 小时前
【剑斩OFFER】算法的暴力美学——力扣 433 题:最小基因变化
数据结构·c++·算法·哈希算法
移幻漂流2 小时前
C/C++内存掌控之道:从内存泄漏到零开销抽象的进阶之路
java·c语言·c++
橘颂TA2 小时前
【剑斩OFFER】算法的暴力美学——力扣 1926 题:迷宫中离入口最近的出口
c++·算法·结构与算法