当前位置: 首页 > article >正文

基于TCP的Qt网络通信

基于TCP的Qt网络通信

在标准C++没有提供专门用于套接字通信的类,所以只能使用操作系统提供的基于C的API函数,但是Qt就不一样了,它是C++的一个框架并且里边提供了用于套接字通信的类(TCP、UDP)这样就使得我们的操作变得更加简单。

使用Qt提供的类进行基于TCP的套接字通信需要用到两个类:(都属于网络模块network)

  • QTcpServer服务器类,用于监听客户端连接以及和客户端建立连接
  • QTcpSocket通信的套接字类(IO操作),客户端、服务器端都需要使用。(与文件操作类QFile同属于同一个祖先QIODevice

一、QTcpServer类

QTcpServer类用于监听客户端连接以及和客户端建立连接

1.1 公共成员函数

  • 1⭐构造函数

    • QTcpServer::QTcpServer(QObject *parent = Q_NULLPTR);
      
  • 2⭐给监听的套接字设置监听

    • //★类似于Socket中的 bind + listen
      bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
      //使用QHostAddress类对IPv4/6进行了封装,可以直接通过点分十进制赋值
      
      // 判断当前对象是否在监听, 是返回true,没有监听返回false
      bool QTcpServer::isListening() const;
      
      //返回监听的服务器地址
      QHostAddress QTcpServer::serverAddress() const;
      // 返回服务器的端口
      quint16 QTcpServer::serverPort() const
      
  • 4⭐得到和客户端建立连接之后用于通信的QTcpSocket套接字对象

    • QTcpSocket套接字对象QTcpServer的一个子对象,当QTcpServer对象析构的时候会自动析构这个子对象,建议用完之后自己手动析构这个通信的QTcpSocket对象。

    • QTcpSocket *QTcpServer::nextPendingConnection();
      //返回值:返回用于通信的套接字对象,建议自己手动释放内存
      
  • 阻塞等待客户端发起的连接请求

    • 不推荐在单线程程序中使用,建议使用非阻塞方式处理新连接,即使用信号 newConnection()

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

1.2 信号

  • 当接受新连接导致错误时,将发射如下信号

    • void QTcpServer::acceptError(QAbstractSocket::SocketError socketError);
      //socketError:描述发生错误的相关信息
      
  • 3⭐每次有新连接可用时都会发出 newConnection() 信号。

    • void QTcpServer::newConnection();
      
  • 有数据可读取时,发送readyRead

1.3 服务器连接的API调用顺序

  • 创建 QTcpServer 实例

    • QTcpServer *server = new QTcpServer(this);
      
  • 监听端口 QTcpServer::listen()

    • server->listen(QHostAddress::Any, 12345)
      
  • 连接 newConnection() 信号

    • connect(server, &QTcpServer::newConnection, this, &MyServer::onNewConnection);
      
  • 处理新连接

    • 在槽函数 onNewConnection() 中获取新的 QTcpSocket,它代表与客户端的连接。

    • void MyServer::onNewConnection() {
          QTcpSocket *clientSocket = server->nextPendingConnection();
          // 连接信号与槽
          connect(clientSocket, &QTcpSocket::readyRead, this, &MyServer::onReadyRead);
          connect(clientSocket, &QTcpSocket::disconnected, this, &MyServer::onDisconnected);
      }
      

二、QTcpSocket

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

继承关系:

image-20210512174459252

2.1 公共成员函数

  • 构造函数

    • QTcpSocket::QTcpSocket(QObject *parent = Q_NULLPTR);
      
  • 连接服务器需要指定服务器端绑定的IP和端口信息

    • [virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port, 
      				OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
      
      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);
      

2.2 信号

  • QTcpSocket进行套接字通信的过程中,如果该类对象发射出readyRead()信号,说明对端发送的数据已到达,之后可以调用 read 函数接收数据。
 void QIODevice::readyRead();
  • 调用connectToHost()函数并成功建立连接之后发出connected()信号。
 void QAbstractSocket::connected();
  • 套接字断开连接时发出disconnected()信号。
void QAbstractSocket::disconnected();

2.3 客户端连接的API调用顺序

  • 创建客户端套接字用于与服务器通信

    • QTcpSocket *socket = new QTcpSocket(this);
      
  • 客户端的信号与槽函数绑定,以便监听事件,例如连接成功、数据接收等。

    • connect(socket, &QTcpSocket::connected, this, &YourClass::onConnected);
      connect(socket, &QTcpSocket::readyRead, this, &YourClass::onReadyRead);
      connect(socket, &QTcpSocket::errorOccurred, this, &YourClass::onError);
      
  • 使用 connectToHost 函数连接到目标服务器。

    • socket->connectToHost("127.0.0.1", 12345);
      

三、通信流程

3.1 服务器端

通信流程:

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

3.2 客户端

通信流程:

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

http://www.kler.cn/a/457346.html

相关文章:

  • mysql连接时报错1130-Host ‘hostname‘ is not allowed to connect to this MySQL server
  • Maven项目集成SQL Server的完整教程:从驱动配置到封装优化
  • 在 SQL 中,区分 聚合列 和 非聚合列(nonaggregated column)
  • SweetAlert2 - 漂亮可定制的 JavaScript 弹窗
  • Swift Combine 学习(四):操作符 Operator
  • TVS二极管选型【EMC】
  • 【论文解读】Arbitrary-steps Image Super-resolution via Diffusion Inversion
  • UE4 编译报错 “Error LNK2019 : 无法解析的外部符号” 一种可能的原因
  • Flask使用的正例和反例
  • SpringBoot整合篇 05、Springboot整合Redission
  • flask-admin 模型视图(modelView)中重写after_model_delete与on_model_delete
  • 力扣-数据结构-6【算法学习day.77】
  • 李永乐线性代数:A可逆,AX=B相关推论和例题解题思路
  • 【探花交友】day06—即时通信
  • [openGauss 学废系列]- openGauss体系结构-多个用户访问同一个数据库
  • Mooncake:kimi后端推理服务的架构设计
  • DOM解析:深入理解文档对象模型
  • Elasticsearch 数据存储底层机制详解
  • C++进阶-【高级语法】
  • 使用GitHub Pages部署静态网站:简易指南
  • 《Vue进阶教程》第二十四课:优化
  • c++ 里 常量转换 const_cast < T > ,要给模板参数 T 传递什么类型呢?
  • iClient3D for Cesium 加载shp数据并拉伸为白模
  • Node.js 工具:在 Windows 11 中配置 Node.js 的详细步骤
  • 影刀进阶应用 | 知乎发布想法
  • EMQX5.X版本性能配置调优参数