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();
相关推荐
郝学胜-神的一滴1 小时前
[简化版 GAMES 104] 现代游戏引擎 06:从Tick时序到邮局模型,拆解确定性世界的底层密码
开发语言·c++·游戏引擎·图形渲染·软件开发·opengl
二十雨辰1 小时前
[Java]-微服务面试题
java·开发语言·微服务
沐风老师1 小时前
从零开始学3dMax插件开发!
c++·3dmax插件·3dmax·maxscript
caimouse1 小时前
ReactOS 图形系统分析(50):画笔子系统 — pen.c
c语言·开发语言·stm32
Zguigo1 小时前
树的前序|中序|后序遍历【使用栈实现】
数据结构·算法
zhanghaha13142 小时前
HTML系列教程:4_什么是 HTML 元素(零基础超详细讲解)
前端·算法·html
TAN-90°-2 小时前
Deep Learning for Computer Vision——Training CNNs and CNN Architectures
人工智能·深度学习·神经网络·算法·机器学习·计算机视觉·cnn
0x3F(小茶)2 小时前
Tokenization(分词算法):一切大语言模型的地基
人工智能·算法·语言模型
tq10862 小时前
从阿罗不可能定理到所有制:动态协调与资源再配置的理论逻辑
笔记