QT中基于TCP的网络通信

QT中基于TCP的网络通信

  • QTcpServer
    • 公共成员函数
    • 信号
  • QTcpSocket
    • 公共成员函数
    • 信号
  • 通信流程
    • 服务器端
      • 通信流程
      • 代码
    • 客户端
      • 通信流程
      • 代码

使用Qt提供的类进行基于TCP的套接字通信需要用到两个类:

QTcpServer:服务器类,用于监听客户端连接以及和客户端建立连接。
QTcpSocket:通信的套接字类,客户端、服务器端都需要使用。
这两个套接字通信类都属于网络模块network。

QTcpServer

QTcpServer类 用于监听客户端连接以及和客户端建立连接,在使用之前先介绍一下这个类提供的一些常用API函数

公共成员函数

构造函数

QTcpServer::QTcpServer(QObject *parent = Q_NULLPTR);

给监听的套接字设置监听

bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
// 判断当前对象是否在监听, 是返回true,没有监听返回false
bool QTcpServer::isListening() const;
// 如果当前对象正在监听返回监听的服务器地址信息, 否则返回 QHostAddress::Null
QHostAddress QTcpServer::serverAddress() const;
// 如果服务器正在侦听连接,则返回服务器的端口; 否则返回0
quint16 QTcpServer::serverPort() const

参数:
address:通过类QHostAddress可以封装IPv4、IPv6格式的IP地址,QHostAddress::Any表示自动绑定
port:如果指定为0表示随机绑定一个可用端口。
返回值:绑定成功返回true,失败返回false

QTcpSocket *QTcpServer::nextPendingConnection();

得到和客户端建立连接之后用于通信的QTcpSocket套接字对象,它是QTcpServer的一个子对象,当QTcpServer对象析构的时候会自动析构这个子对象,当然也可自己手动析构,建议用完之后自己手动析构这个通信的QTcpSocket对象。

bool QTcpServer::waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR);

阻塞等待客户端发起的连接请求,不推荐在单线程程序中使用,建议使用非阻塞方式处理新连接,即使用信号 newConnection() 。

参数:
msec:指定阻塞的最大时长,单位为毫秒(ms)
timeout:传出参数,如果操作超时timeout为true,没有超时timeout为false

信号

当接受新连接导致错误时,将发射如下信号。socketError参数描述了发生的错误相关的信息。

[signal] void QTcpServer::acceptError(QAbstractSocket::SocketError socketError);

每次有新连接可用时都会发出 newConnection() 信号。

[signal] void QTcpServer::newConnection();

QTcpSocket

QTcpSocket是一个套接字通信类,不管是客户端还是服务器端都需要使用。在Qt中发送和接收数据也属于IO操作(网络IO),先来看一下这个类的继承关系:

在这里插入图片描述

公共成员函数

构造函数

QTcpSocket::QTcpSocket(QObject *parent = Q_NULLPTR);

连接服务器,需要指定服务器端绑定的IP和端口信息。

[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);[virtual] void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode = ReadWrite);

在Qt中不管调用读操作函数接收数据,还是调用写函数发送数据,操作的对象都是本地的由Qt框架维护的一块内存。因此,调用了发送函数数据不一定会马上被发送到网络中,调用了接收函数也不是直接从网络中接收数据,关于底层的相关操作是不需要使用者来维护的。

接收数据

// 指定可接收的最大字节数 maxSize 的数据到指针 data 指向的内存中
qint64 QIODevice::read(char *data, qint64 maxSize);
// 指定可接收的最大字节数 maxSize,返回接收的字符串
QByteArray QIODevice::read(qint64 maxSize);
// 将当前可用操作数据全部读出,通过返回值返回读出的字符串
QByteArray QIODevice::readAll();

发送数据

// 发送指针 data 指向的内存中的 maxSize 个字节的数据
qint64 QIODevice::write(const char *data, qint64 maxSize);
// 发送指针 data 指向的内存中的数据,字符串以 \0 作为结束标记
qint64 QIODevice::write(const char *data);
// 发送参数指定的字符串
qint64 QIODevice::write(const QByteArray &byteArray);

信号

在使用QTcpSocket进行套接字通信的过程中,如果该类对象发射出readyRead()信号,说明对端发送的数据达到了,之后就可以调用 read 函数接收数据了。

[signal] void QIODevice::readyRead();

调用connectToHost()函数并成功建立连接之后发出connected()信号。

[signal] void QAbstractSocket::connected();

在套接字断开连接时发出disconnected()信号。

[signal] void QAbstractSocket::disconnected();

通信流程

在这里插入图片描述

服务器端

通信流程

  1. 创建套接字服务器QTcpServer对象
  2. 通过QTcpServer对象设置监听,即:QTcpServer::listen()
  3. 基于QTcpServer::newConnection()信号检测是否有新的客户端连接
  4. 如果有新的客户端连接调用QTcpSocket
  5. *QTcpServer::nextPendingConnection()得到通信的套接字对象
  6. 使用通信的套接字对象QTcpSocket和客户端进行通信

代码

服务器端的窗口界面如下图所示:
在这里插入图片描述

QtServer.pro文件

在这里插入图片描述

mainwindow.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QLabel>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_setListen_clicked();void on_sendMsg_clicked();private:Ui::MainWindow *ui;QTcpServer* m_s;QTcpSocket* m_tcp;QLabel* m_status;
};
#endif // MAINWINDOW_H

main.cpp文件

#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

mainwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);ui->port->setText("8000"); //先设置一个端口号setWindowTitle("服务器");//创建监听的服务器对象m_s = new QTcpServer(this); //指定父对象,不需要再去管内存的释放//等待客户端链接,连接上会发送一个信号newConnectionconnect(m_s,&QTcpServer::newConnection,this,[=](){m_tcp = m_s->nextPendingConnection(); //得到可供通讯的套接字对象m_status->setPixmap(QPixmap(":/connect.png").scaled(20,20)); //更改链接状态//检测是否可以接收数据connect(m_tcp,&QTcpSocket::readyRead,this,[=](){QByteArray data = m_tcp->readAll(); //全部读出来ui->record->append("客户端say: " + data);  //显示在历史记录框中});//对端断开链接时会,TcpSocket会发送一个disconnect信号connect(m_tcp,&QTcpSocket::disconnected,this,[=](){m_tcp->close(); //关闭套接字m_tcp->deleteLater(); //释放m_tcpm_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20)); //更改链接状态});});//状态栏m_status = new QLabel;//给标签设置图片m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20));  //scaled设置图片大小//将标签设置到状态栏中ui->statusbar->addWidget(new QLabel("连接状态: "));ui->statusbar->addWidget(m_status);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_setListen_clicked()
{unsigned short port = ui->port->text().toUShort();m_s->listen(QHostAddress::Any,port); //开始监听ui->setListen->setDisabled(true);  //监听之后设置为不可用状态
}void MainWindow::on_sendMsg_clicked()
{QString msg = ui->msg->toPlainText(); //以纯文本的方式把数据读出来m_tcp->write(msg.toUtf8());ui->record->append("服务器say: " + msg);  //显示在历史记录框中
}

mainwindow.ui文件
在这里插入图片描述

客户端

通信流程

  1. 创建通信的套接字类QTcpSocket对象
  2. 使用服务器端绑定的IP和端口连接服务器QAbstractSocket::connectToHost()
  3. 使用QTcpSocket对象和服务器进行通信

代码

客户端的窗口界面如下图所示:
在这里插入图片描述

QtClient.pro文件
在这里插入图片描述
mainwindow.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTcpSocket>
#include <QLabel>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_sendMsg_clicked();void on_connect_clicked();void on_disconnect_clicked();private:Ui::MainWindow *ui;QTcpSocket* m_tcp;QLabel* m_status;
};
#endif // MAINWINDOW_H

main.cpp文件

#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

mainwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"#include <QHostAddress>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);ui->port->setText("8000"); //先设置一个端口号ui->ip->setText("127.0.0.1"); //设置本地循环ipsetWindowTitle("客户端");ui->disconnect->setDisabled(true);//断开连接按钮不可用//创建监听的服务器对象m_tcp = new QTcpSocket(this); //指定父对象,不需要再去管内存的释放//检测是否可以接受数据 当 m_tcp 发送给出readyRead信号,就说明有信号到达了connect(m_tcp,&QTcpSocket::readyRead,this,[=](){QByteArray data = m_tcp->readAll(); //全部读出来ui->record->append("服务器say: " + data);  //显示在历史记录框中});//对端断开链接时会,TcpSocket会发送一个disconnect信号connect(m_tcp,&QTcpSocket::disconnected,this,[=](){m_tcp->close(); //关闭套接字//m_tcp->deleteLater(); // 指定了父对象,不需要手动释放 m_tcpm_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20)); //更改链接状态ui->record->append("服务器已经和客户端断开了连接...");ui->connect->setDisabled(false); //连接按钮可用ui->disconnect->setEnabled(false); //断开连接按钮不可用});//当 m_tcp 发送一个 connected 信号后,就说明已经连接上服务器connect(m_tcp,&QTcpSocket::connected,this,[=](){m_status->setPixmap(QPixmap(":/connect.png").scaled(20,20));  //scaled设置图片大小ui->record->append("已经成功连接到了服务器...");ui->connect->setDisabled(true); //连接按钮不可用ui->disconnect->setEnabled(true); //断开连接按钮可用});//状态栏m_status = new QLabel;//给标签设置图片m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20,20));  //scaled设置图片大小//将标签设置到状态栏中ui->statusbar->addWidget(new QLabel("连接状态: "));ui->statusbar->addWidget(m_status);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_sendMsg_clicked()
{QString msg = ui->msg->toPlainText(); //以纯文本的方式把数据读出来m_tcp->write(msg.toUtf8());ui->record->append("客户端say: " + msg);  //显示在历史记录框中
}void MainWindow::on_connect_clicked()
{QString ip = ui->ip->text();unsigned short port = ui->port->text().toUShort();m_tcp->connectToHost(QHostAddress(ip),port);
}void MainWindow::on_disconnect_clicked()
{m_tcp->close();ui->connect->setDisabled(false);ui->disconnect->setEnabled(false);
}

mainwindow.ui文件
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/2559.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

赛劲SEJINIGB零背隙滚轮齿条齿圈产品助力高精度运动平台

在高度精密化的工业时代&#xff0c;传统齿轮齿条系统所面临的背隙、摩擦粉尘、润滑等问题愈发凸显&#xff0c;这些问题不仅限制了设备的精度和稳定性&#xff0c;还对生产效率和产品质量造成严重影响。为此&#xff0c;赛劲SEJINIGB经过长期研发和技术积累&#xff0c;推出了…

消息队列 Kafka 入门篇(二) -- 安装启动与可视化工具

一、Windows 10 环境安装 1、下载与解压 首先&#xff0c;访问Apache Kafka的官方下载地址&#xff1a; https://kafka.apache.org/downloads 在本教程中&#xff0c;我们将使用kafka_2.13-2.8.1版本作为示例。下载完成后&#xff0c;解压到您的工作目录的合适位置&#xff…

ubuntu下chronyc tracking报文详解

在ubuntu下使用chronyc进行时钟的同步操作&#xff0c;下面是执行chrony tracking返回结果&#xff1a; Reference ID : AC1005E7 (ntpxx) Stratum : 12 Ref time (UTC) : Tue Apr 23 07:24:09 2024 System time : 0.000001974 seconds slow of NTP time Last …

如何在Windows 8/10/11上启用和禁用内置访客帐户?这里提供几种方法

你的Windows上有一个内置的guest帐户&#xff0c;可以帮助计算机上没有帐户的人登录。当然&#xff0c;你可以打开或关闭它。本文将介绍一些在Windows 8/10/11计算机中启用和禁用内置guest帐户的有用方法&#xff0c;供你更好地参考。 如何启用内置来宾帐户 在本地组策略中启…

Django中的事务

1 开启全局的事务 DATABASES {default: {ENGINE: django.db.backends.mysql, # 使用mysql数据库NAME: tracerbackend, # 要连接的数据库USER: root, # 链接数据库的用于名PASSWORD: 123456, # 链接数据库的用于名HOST: 192.168.1.200, # mysql服务监听的ipPORT: 3306, …

面向多源异质遥感影像地物分类的自监督预训练方法

源自&#xff1a;测绘学报 作者&#xff1a;薛志祥, 余旭初, 刘景正, 杨国鹏, 刘冰, 余岸竹, 周嘉男, 金上鸿 摘 要 近年来,深度学习改变了遥感图像处理的方法。由于标注高质量样本费时费力,标签样本数量不足的现实问题会严重影响深层神经网络模型的性能。为解决这一突出矛盾…

Linux防火墙相关命令以及ip白名单配置

Linux防火墙相关命令以及ip白名单配置 firewall防火墙基础命令查看防火墙的服务状态查看防火墙的状态服务的开启、关闭和重启查看防火墙规则端口的查询、开放和关闭重启防火墙 防火墙白名单配置部分参数介绍 firewall防火墙基础命令 查看防火墙的服务状态 systemctl status f…

使用 vllm 本地部署 cohere 的 command-r

使用 vllm 本地部署 cohere 的 command-r 0. 引言1. 安装 vllm2. 本地部署 cohere 的 command-r3. 使用 cohere 的 command-r 0. 引言 此文章主要介绍使用 使用 vllm 本地部署 cohere 的 command-r。 1. 安装 vllm 创建虚拟环境&#xff0c; conda create -n myvllm python…

nn.Embedding, nn.Parameter,nn.linear的区别

还没总结&#xff1a; 先贴上参考帖子&#xff1a; Difference between Embedding formulations Issue #60 lucidrains/vit-pytorch GitHub https://audreywongkg.medium.com/pytorch-nn-parameter-vs-nn-linear-2131e319e463 Differences between nn.Embedding and nn.…

网络安全之CSRFSSRF漏洞(上篇)(技术进阶)

目录 一&#xff0c;CSRF篇 二&#xff0c;认识什么是CSRF 三&#xff0c;实现CSRF攻击的前提 四&#xff0c;实战演练 【1】案例1 【2】案例2 【3】案例3 【4】案例4&#xff08;metinfo&#xff09; 一&#xff0c;CSRF篇 二&#xff0c;认识什么是CSRF CSRF&#x…

Diff算法深度剖析:优化DOM操作的关键

React的Diff算法是用于比较新旧虚拟DOM树&#xff0c;以找出需要进行更新的部分。它通过遍历树的节点&#xff0c;并比较节点属性和内容&#xff0c;来确定节点是否需要进行更新。 React的Diff算法采用了一些优化策略&#xff0c;以减少不必要的DOM更新&#xff0c;提高性能。…

程序员过了35岁没人要?“这行越老越香”

程序员35岁失业&#xff1f;参加完OceanBase开发者大会&#xff0c;我又悟了&#xff01; 周六参加了OceanBase2024 开发者大会的现场&#xff0c;来之前我其实挺忐忑的&#xff0c;我觉得一个数据库产品的发布会&#xff0c;能有什么新鲜的东西&#xff1f; 踏入酒店的那一刻&…

vue 动态改变css样式

文章目录 问题描述 问题描述 大家好&#xff01;今天是2024年4月26日|农历三月十六&#xff0c;时间过得好快&#xff0c;今天这博文主要动态改变css样式&#xff0c;具体实现效果如下&#xff1a; 在data里面声明一个isShow:true属性&#xff0c;通过isShow显示不同的图片 isS…

RouteRecordRaw

最近在学习并使用typescript&#xff0c;接触到了很多新类型&#xff0c;今天在学习过程中&#xff0c;看到了RouteRecordRaw这个类型&#xff0c;写篇博客记录一下。 RouteRecordRaw RouteRecordRaw 是 Vue Router 4 中新增的一个类型定义。 它是用于定义路由记录的。 在 Vu…

Pinia 深度剖析:Vue.js 应用状态管理的全面指南

一、pinia简介 Pinia 是一个专门为 Vue.js 应用程序设计的状态管理库。它的设计理念是简化状态管理过程&#xff0c;提供一种清晰、可维护的方式来管理应用程序中的数据。 二、安装与创建 1.你可以通过 npm 或者 yarn 来安装 Pinia&#xff1a; npm install pinia # 或者 y…

上位机工作感想-从C#到Qt的转变-2

2.技术总结 语言方面 最大收获就是掌握了C Qt编程&#xff0c;自己也是粗看了一遍《深入理解计算机系统》&#xff0c;大致了解了计算机基本组成、虚拟内存、缓存命中率等基基础知识&#xff0c;那本书确实有的部分看起来很吃力&#xff0c;等这段时间忙完再研读一遍。对于封装…

消消乐算法总结

前言 最近在工作中遇到一个问题&#xff0c;做一个消消乐的demo项目&#xff0c;连续相同数目超过四个后就要消除。我在网上看了很多解决方案&#xff0c;有十字形&#xff0c;横向&#xff0c;纵向&#xff0c;梯形搜索。越看越迷糊。这不是用一个BFS就能解决的问题吗&#x…

linux下tcp/udp协议网络通信接口封装+日志打印对象

目录 引入 代码 log.hpp代码 引入 我们可以把之前写过的代码拿过来整合一下,直接封装出网络套接字的接口 这样之后再使用的话,直接调用接口即可这里写的是tcp协议,也可以修改socket函数里的参数,改为udp协议 代码 #pragma once#include <iostream> #include <stri…

实现 vuereact 混合开发项目步骤-微前端

微前端是一种将多个小型前端应用组合成一个大型应用的架构方式。它允许团队独立开发、测试、部署和维护应用的各个部分。Vue.js 和 React 是两个流行的前端框架&#xff0c;它们可以在同一微前端架构下协同工作。 一、常规流程 1. 项目规划 确定项目的范围和目标。 设计应用的…

Qt:实现TCP同步与异步读写消息

一、异步读写 在 Qt 中实现 TCP 客户端和服务器的同步和异步读写消息涉及使用 QTcpSocket 和 QTcpServer 类。这两个类提供了用于建立 TCP 连接、发送和接收数据的功能。下面是一个简单的示例&#xff0c;演示了如何在 Qt 中实现 TCP 客户端和服务器的同步和异步读写消息&…