Qt 学习笔记 - 第四章 - Qt的三驾马车之 - 网络编程

Qt 学习笔记全系列传送门:

1、TCP 通信

1.1 TCP 编程的特点

  • 包含服务器和客户端
  • 使用时需要在工程文件中引入 QT += network并在使用时导入包
  • 需要使用到的类有
    • QTcpServer
    • QTcpSocket

1.2 TCP 服务器案例

需要先定义并在构造中初始化QTcpServer *tcpServerQTcpSocket *tcpSocket

// 这里传入 this 时,父对象被删除时子对象也会被删除,省去了delete的麻烦
tcpServer = new QTcpServer(this);
tcpSocket = new QTcpSocket(this);
  • 工程文件

    QT       += core gui network
    
  • UI

    1. 接收框,只读

    2. 端口号输入框和提示文字

    3. 发送窗口

    4. 按钮,打开服务器、关闭服务器、发送

    5. 控件改名

  • 逻辑功能

    1. 监听:槽函数,点击打开服务器时,需要监听对应端口是否被访问

      Widget::Widget(QWidget *parent) :
          QWidget(parent),
          ui(new Ui::Widget)
      {
          ui->setupUi(this);
      
          // 新建tcpServer和tcpSocket的对象,成员属性在头文件中已定义,细节不表
          tcpServer = new QTcpServer(this);
          tcpSocket = new QTcpSocket(this);
      }
      
      void Widget::on_openBt_clicked()
      {
          // 开启监听,监听所有人的连接,参数指定所有人和一个无符号整型端口
          tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toUInt());
      }
      
    2. 接收:包含获取和展示两个部分

      • 获取

        Widget::Widget(QWidget *parent) :
            QWidget(parent),
            ui(new Ui::Widget)
        {
            ui->setupUi(this);
        
            tcpServer = new QTcpServer(this);
            tcpSocket = new QTcpSocket(this);
        
            // 当监测到新的连接产生的信号时,调用槽函数newConnection_Slot()
            connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection_Slot()));
        
        }
        
        void Widget::newConnection_Slot()
        {
            // 获取到已经连接的客户端的Socket
            tcpSocket = tcpServer->nextPendingConnection();
        
            // 当存在可读数据时,调用槽函数readyRead_Slot(),用于展示到接收框中
            connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readyRead_Slot()));
        
        }
        
      • 展示到接收框

        void Widget::readyRead_Slot()
        {
            // 读取tcpSocket中的内容,使用字符串接收
            QString buf = tcpSocket->readAll();
        
            // 将读取到的信息展示到接收框中
            ui->recvEdit->appendPlainText(buf);
        
        }
        
    3. 发送

      void Widget::on_sendBt_clicked()
      {
          // 需要转成 char*
          tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
      }
      
    4. 关闭

      void Widget::on_closeBt_clicked()
      {
          tcpServer->close();
          tcpSocket->close();
      }
      

1.3 TCP 客户端案例

  • 工程文件

    QT       += core gui network
    
  • UI

    1. 接收框,只读

    2. 端口号输入框和提示文字、IP地址输入框和提示文字

    3. 发送窗口

    4. 按钮,打开服务器、关闭服务器、发送

    5. 控件改名

  • 逻辑功能

    需要先定义并在构造中初始化QTcpSocket *tcpSocket

    tcpSocket = new QTcpSocket(this);

    1. 连接

      void Widget::on_openBt_clicked()
      {
          // 点击打开客户端时,应连接服务器,取界面上的ip和端口,端口要转Uint
          tcpSocket->connectToHost(ui->ipEdit->text(), ui->portEdit->text().toUInt());
      
          // 当监听到连接成功的信号connected()时,调用槽函数connected_Slot()
          connect(tcpSocket, SIGNAL(connected()), this, SLOT(connected_Slot()));
      }
      
    2. 接收

      void Widget::connected_Slot()
      {
          // 当监听到有东西可读的信号readyRead()时,调用槽函数
          connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readyRead_Slot()));
      }
      
      void Widget::readyRead_Slot()
      {
          // 读取tcpSocket中的信息,展示到页面上
          ui->recvEdit->appendPlainText(tcpSocket->readAll());
      }
      
    3. 发送

      void Widget::on_sendBt_clicked()
      {
          // 发送时将发送框中的内容转为 char* 写入tcpSocket
          tcpSocket->write(ui->sendEdit->text().toLocal8Bit());
      }
      
    4. 关闭

      void Widget::on_closeBt_clicked()
      {
          tcpSocket->close();
      }
      

2、UDP 通信

1.1 UDP 编程的特点

  • 不分客户端和服务器

  • 使用时需要在工程文件中引入 QT += network并在使用时导入包

  • 需要使用 QUdpSocket 类

1.2 UDP 客户端

需要先定义并在构造中初始化QUdpSocket *udpSocket

udpSocket = new QUdpSocket(this);

  • 工程文件

    QT       += core gui network
    
  • UI

    1. 接收框,只读
    2. 端口号输入框和提示文字、目标端口号输入框和提示文字、IP地址输入框和提示文字
    3. 发送窗口
    4. 按钮,打开服务器、关闭服务器、发送
    5. 控件改名
  • 逻辑功能

    1. 启动

      void Widget::on_openBt_clicked()
      {
          // 将端口号绑定到Socket
          if (udpSocket->bind(ui->localPortEdit->text().toUInt())) {
              QMessageBox::information(this, "提示", "成功");
          } else {
              QMessageBox::information(this, "提示", "失败");
          }
          // 关联readyRead信号,有可读信号调用槽函数
          connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readyRead_slot()));
      }
      
    2. 接收

      void Widget::readyRead_slot()
      {
          // hasPendingDatagrams()用于判断是否读取完,若没有读完则返回true
          while (udpSocket->hasPendingDatagrams()) {
              QByteArray arr;
              // 将数组调整为和 udpSocket 中剩下的数据大小一样
              arr.resize(udpSocket->pendingDatagramSize());
              // 将udpSocket中的信息读取到arr中,参数为接收数组和接收的数据长度
              udpSocket->readDatagram(arr.data(), arr.size());
              // 将信息写到页面上
              QString buffer = arr.data();
              ui->recvEdit->appendPlainText(buffer);
          }
      }
      
    3. 发送

      void Widget::on_sendBt_clicked()
      {
          qunit16 port = ui->aimPortEdit->text().toUInt();
          QString sendbuffer = ui->sendEdit->text();
          QHostAddress addr;
          addr.setAddress(ui->aimIpEdit->text());
      
          // 发送的内容需要转成 char*
          udpSocket->writeDatagram(sendbuffer.toLocal8Bit().data(), sendbuffer.length(), addr, port);
      }
      
    4. 关闭

      void Widget::on_closeBt_clicked()
      {
          udpSocket->close();
      }
      
posted @ 2023-03-15 14:41  Dandelion_000  阅读(147)  评论(0编辑  收藏  举报