6. Qt网络编程

网络编程概览

网络编程(network programming)是在一定协议下实现两台计算机通信的程序。Qt 中所有 Socket 类都是非阻塞的,通信过程由事件驱动(数据到达发信号)。使用网络类必须在 .pro 文件添加 QT += network。

pro 加 QT += network,否则编译报"找不到头文件"。

三个核心类分工:

  • QTcpServer(TCP 服务器套接字)------服务器端,监听连接。

  • QTcpSocket(TCP 套接字)------客户端连接,也用于服务器与客户端通信。

  • QUdpSocket(UDP 套接字)------UDP 通信,服务器、客户端都用它。

TCP 服务器流程

TCP 服务器(QTcpServer)五个步骤:①创建套接字 → ②listen 监听 → ③newConnection 信号检测连接、nextPendingConnection 取客户端 → ④读写数据 → ⑤close 关闭。

listen(地址, 端口):进入监听模式,如 listen(QHostAddress("127.0.0.1"), 8000)。127.0.0.1 是本机回环地址(只在本机通信测试用)。

newConnection 信号:有客户端连接时发射;槽里调 nextPendingConnection() 取客户端 QTcpSocket*。

取到客户端后要再 connect 它的 readyRead 信号,有数据到达时触发读取。

客户端信息:cli->peerAddress().toString()(客户端 IP)、cli->peerPort()(客户端端口)。

发送:cli->write(数据);接收:readAll()(一次读全部)。

关闭:ser->close()(停止监听)、cli->close()(断开连接)。

TCP 客户端流程

TCP 客户端(QTcpSocket)四步:①创建套接字 → ②connectToHost 连接服务器 → ③readyRead 收 / write 发 → ④close 关闭。

connectToHost(服务器地址, 端口):发起连接,如 connectToHost(QHostAddress("127.0.0.1"), 8000)。

收发与服务器端相同:readyRead 信号 + readAll() 接收;write() 发送。

发送中文要转编码:write(str.toUtf8())(QString 转 UTF-8 字节)。

同步(阻塞)方式:非 GUI/多线程中可用 waitForConnected() 等 waitFor... 系列函数暂停线程等待操作完成(一般 GUI 用信号异步方式即可)。

复制代码
 // ===== 服务器端 =====
 QTcpServer *ser = new QTcpServer(this);
 ser->listen(QHostAddress("127.0.0.1"), 8000);      // 监听本机8000端口
 connect(ser, &QTcpServer::newConnection, this, &server::recv_conn);
 ​
 void server::recv_conn() {                         // 有客户端连入
     cli = ser->nextPendingConnection();            // 取客户端 socket
     qDebug() << cli->peerAddress().toString();     // 客户端 IP
     connect(cli, &QTcpSocket::readyRead, this, &server::recv_data);
 }
 void server::recv_data() {                         // 收到数据
     QByteArray rdata = cli->readAll();             // 读全部数据
     ui->txt_recv->append(rdata);
 }
 void server::on_btn_send_clicked() {               // 发送
     cli->write(ui->txt_send->text().toUtf8());
 }
 ​
 // ===== 客户端 =====
 QTcpSocket *cli = new QTcpSocket(this);
 cli->connectToHost(QHostAddress("127.0.0.1"), 8000);  // 连接服务器
 connect(cli, &QTcpSocket::readyRead, this, &tcpClient::recv_data);
 void tcpClient::recv_data() {
     QString rstr = cli->readAll();
     ui->txt_recv->append(rstr);
 }
sender() 获取信号发送者

QObject::sender() 是 QObject 的成员函数,返回当前正在执行的槽是由哪个对象发出的信号触发的(指针)。

只能在槽函数内调用(信号触发时有效)。

返回 QObject*,需强转回实际类型:cli = (QTcpSocket*)sender();

复制代码
 void server::recv_data() {
     // 多个客户端共用一个槽时,用 sender() 区分是谁发来的
     cli = (QTcpSocket*)sender();   // 强转回 QTcpSocket*
     QByteArray rdata = cli->readAll();
     ui->txt_recv->append(rdata);
 }
网络数据的接收与发送细节

数据先进入发送缓冲区,之后由操作系统送往远端;flush() 强制立刻送走。

接收缓冲区大小可用 setReadBufferSize(字节数) 设置。

错误处理:error() 返回错误类型、errorString() 返回错误提示字符串。

接收线程在后台运行,完成后再交给主线程,不阻塞界面。

UDP 通信
UDP 收发流程

UDP(User Datagram Protocol,用户数据报协议)无连接,服务器/客户端概念淡化------两端做的工作大致相同:①创建 QUdpSocket → ②bind 绑定端口 → ③readDatagram 收 / writeDatagram 发 → ④close 关闭。

bind(地址, 端口):把 socket 绑定到本机某端口,才能收到发给该端口的数据。

接收:readDatagram(缓存, 最大字节, &发送方地址, &发送方端口)------返回实际收到的字节数;pendingDatagramSize() 可先查待收数据大小来准备缓存。

发送:writeDatagram(数据, 目标地址, 目标端口)。

发送方地址用 QHostAddress,端口用 quint16(无符号 16 位整数,0~65535)。

接收后从 addr/port 参数取到"谁发来的",可直接回发给对方。

复制代码
 // ===== UDP 服务端 =====
 QUdpSocket *ser = new QUdpSocket(this);
 ser->bind(QHostAddress("127.0.0.1"), 8000);   // 绑定本机端口
 connect(ser, &QUdpSocket::readyRead, this, &udp_server::recv_data);
 ​
 void udp_server::recv_data() {
     char buff[100] = {0};
     // 读数据,同时取出发送方地址和端口
     int ret = ser->readDatagram(buff, 100, &addr, &port);
     if (ret != -1)                        // 成功才处理
         ui->txt_recv->append(buff);
 }
 void udp_server::on_btn_send_clicked() {
     QString str = ui->txt_send->text().trimmed();
     // 发给刚才收到数据的地址和端口(回发)
     ser->writeDatagram(str.toUtf8().data(), 100, addr, port);
 }
 ​
 // ===== UDP 客户端(与服务端几乎一样)=====
 QUdpSocket *cli = new QUdpSocket(this);
 addr.setAddress("127.0.0.1");             // 目标地址
 port = 8000;                              // 目标端口
 cli->writeDatagram(str.toUtf8().data(), 100, addr, port);  // 发送
TCP 与 UDP 对比
对比点 TCP UDP
连接 需建立连接(connectToHost / listen) 无连接,直接收发
可靠性 可靠(不丢包、有序) 不可靠(可能丢包)
服务器类 QTcpServer(监听) 无专门类,QUdpSocket 通用
客户端类 QTcpSocket QUdpSocket
绑定端口 服务器 listen 两端都要 bind
收发函数 readAll() / write() readDatagram() / writeDatagram()
四、文本编辑 QTextEdit 小功能
复制代码
 ui->textEdit->copy();    // 复制选中内容
 ui->textEdit->paste();   // 粘贴
 ui->textEdit->undo();    // 撤销
 ui->textEdit->zoomIn();  // 放大
 ui->textEdit->zoomOut(); // 缩小
 ​
 // 保存到文件:文字转 UTF-8 字节再写
 QString path = QFileDialog::getSaveFileName();  // 选保存路径
 QFile file(path);
 file.open(QIODevice::WriteOnly);
 file.write(ui->textEdit->toPlainText().toUtf8().data(),  // 写内容
            ui->textEdit->toPlainText().size());
 file.close();
相关推荐
老赵的博客24 分钟前
c++ QT之动态库加载问题
c++·qt
菜鸟~noob23331 分钟前
【电子战】 第01篇:噪声、门限与虚警/检测概率(PFA/PD)【含matlab代码】
开发语言·matlab
奇牙coding12333 分钟前
GPT-6-Astra API 接入教程:OpenRouter 路由配置 + Python/curl 示例 + 静默降级踩坑
开发语言·python·gpt·ai
(Charon)38 分钟前
【C++】定时器进阶:使用最小堆管理定时任务
c++·算法
hansang_IR1 小时前
【题解】 [省选联考 2021 A/B 卷] 卡牌游戏
c++·算法
这个DBA有点耶1 小时前
COUNT慢不是因为用了*,是这5个原因——1000万行数据实测+执行计划深度解析
数据库·mysql·算法
贾伟康1 小时前
【口算王|01】HarmonyOS ArkTS 口算题生成实战:按年级、运算类型和难度生成可控题目
算法·harmonyos·arkts·随机生成·口算题
lzx_0021 小时前
C++11(一)
开发语言·c++·算法
529宝宝起名网2 小时前
用 Python 实现名字寓意评分算法:基于 NLP 语义分析的名字内涵深度评估
python·算法·自然语言处理
未来之窗软件服务2 小时前
计算机二级[英文]-C 字符串移动—东方仙盟
c语言·开发语言·仙盟创梦ide·东方仙盟