QT网络编程

QT网络编程

QT网络编程需要在配置文件中添加网络模块的配置文件

#---添加网络模块配置---
QT       += network

QHostInfo和QNetworkInterface可获取本地主机或其它主机的相关信息

QHostInfoQNetWorkInterface获取网络信息demo

  • 界面设计
    729394-20190910104022649-1592209624.jpg

  • 获取主机按钮槽函数

      //获取主机信息按钮事件
      void MainWindow::on_btn_host_clicked()
      {
          //hostinfo获取主机的信息
          QString hostName=QHostInfo::localHostName();//获取本机的主机名
          ui->plainTextEdit->appendPlainText("主机名为:"+hostName+"\n");
    
          QHostInfo hostInfo=QHostInfo::fromName(hostName);//通过主机名来获取主机的hostinfo
          QList<QHostAddress> addList=hostInfo.addresses();//通过主机的host信息来获取本机IP地址列表
          if(!addList.isEmpty())//如果主机地址列表不为空
          {
              for(int i=0;i<addList.length();i++)
              {
                  QHostAddress hostAddress=addList.at(i); //每一项是一个hostAddress
                  bool show=ui->cbxShowIPV4->isChecked();//是否选中
                  if(show)
                  {
                      show=(QAbstractSocket::IPv4Protocol==hostAddress.protocol());
                  }
                  else 
                  {
                      show=true;
                  }
                  if(show)
                  {
                      ui->plainTextEdit->appendPlainText("协议:"+protocalName(hostAddress.protocol()));
                      ui->plainTextEdit->appendPlainText("本机IP地址:"+hostAddress.toString());
                      ui->plainTextEdit->appendPlainText("");
                  }
              }
          }  
      }  
  • 按照主机名,IP地址,域名来查找主机信息

      //按照主机的主机名,IP地址,域名来查找主机信息
      void MainWindow::on_btnFindIP_clicked()
      {
          //查找主机信息
          QString hostName=ui->txtHostName->text();
          ui->plainTextEdit->appendPlainText("正在查找"+hostName+"主机的信息");
          //lookupHost()以异步的方式查找主机信息,查找完成后通过信号通知槽函数
          QHostInfo::lookupHost(hostName,this,SLOT(lookedUpHostInfo(QHostInfo)));
      }  
  • 查找主机信息槽函数

      //查找主机信息
      void MainWindow::lookedUpHostInfo(const QHostInfo & hostInfo)
      {
          QList<QHostAddress> listAdd=hostInfo.addresses();
          if(!listAdd.isEmpty())
          {
              for(int i=0;i<listAdd.length();i++)
              {
                  QHostAddress add=listAdd.at(i);
                  bool show=ui->cbxShowIPV4->isChecked();
                  if(show)
                  {
                      show=(QAbstractSocket::IPv4Protocol==add.protocol());
                  }
                  else
                  {
                      show=true;
                  }
                  if(show)
                  {
                      ui->plainTextEdit->appendPlainText("协 议:"+protocalName(add.protocol()));
                      ui->plainTextEdit->appendPlainText(add.toString());
                      ui->plainTextEdit->appendPlainText("");
                  }
              }
          }
      }  
  • //只获取IP地址QNetworkInterface::allAddress()

      //只获取IP地址QNetworkInterface::allAddress()
      void MainWindow::on_btn_network_clicked()
      {
          QList<QHostAddress> listHost=QNetworkInterface::allAddresses();
          if(!listHost.isEmpty())
          {
              for(int i=0;i<listHost.length();i++)
              {
                  QHostAddress address=listHost.at(i);
                  bool show=ui->cbxShowIPV4->isChecked();
                  if(show)
                  {
                      show=(QAbstractSocket::IPv4Protocol==address.protocol());
                  }
                  else
                  {
                      show=true;
                  }
                  if(show)
                  {
                      ui->plainTextEdit->appendPlainText("协 议:"+protocalName(address.protocol()));
                      ui->plainTextEdit->appendPlainText("IP地址:"+address.toString());
                      ui->plainTextEdit->appendPlainText("");
                  }
              }
    
          }
      }  
  • QNetworkInterface可以获取应用程序所在主机的所有网络接口,包括其子网掩码和广播地址等

      void MainWindow::on_btnNetwoklInterface_clicked()
      {
          QList<QNetworkInterface> list=QNetworkInterface::allInterfaces();//获取所有的网络接口
          for(int i=0;i<list.length();i++)
          {
              QNetworkInterface interface=list.at(i);
              if(!interface.isValid())
              {
                  continue;
              }
    
              ui->plainTextEdit->appendPlainText("设备名称:"+interface.humanReadableName());
              ui->plainTextEdit->appendPlainText("硬件地址:"+interface.hardwareAddress());
              QList<QNetworkAddressEntry> entryList=interface.addressEntries();
              for(int j=0;j<entryList.length();j++)
              {
                  QNetworkAddressEntry aEntry=entryList.at(j);
                  ui->plainTextEdit->appendPlainText(" IP 地址:"+aEntry.ip().toString());
                  ui->plainTextEdit->appendPlainText(" 子网掩码:"+aEntry.netmask().toString());
                  ui->plainTextEdit->appendPlainText(" 广播地址:"+aEntry.broadcast().toString()+"\n");
              }
              ui->plainTextEdit->appendPlainText("\n");
          }
      }  

Qt TCP编程

TCP Client编程

  • TCP Client客户端界面如下图:
    729394-20190910104043868-376123702.jpg

  • 连接服务器

      //连接服务器
      void MainWindow::on_actConnectServer_triggered()
      {
          QString addr=ui->cbbxServerAdd->currentText();//服务器IP地址
          quint16 port=ui->spbPort->value();//服务器端口号
          tcpSocket->connectToHost(addr,port);//连接服务器
          lblSocketState->setText("Socket状态:正在连接");
      }  
  • 客户端连接上服务器后tcpClient会发射connected()信号,对应的槽函数如下:

      void MainWindow::onConnected()
      {
          ui->plainTextEdit->appendPlainText("**已连接到服务器");
          ui->plainTextEdit->appendPlainText("**peer address:"+tcpSocket->peerAddress().toString());
          ui->plainTextEdit->appendPlainText("**peer port:"+QString::number(tcpSocket->peerPort()));
          ui->actConnectServer->setEnabled(false);
          ui->actDisconnect->setEnabled(true);
          lblSocketState->setText("Socket状态:已连接");
      }  
  • 客户端连接状态发生变化会触发stateChanged(QAbstractSocket::SocketState))信号,对应的槽函数代码如下

      void MainWindow::onSocketStateChanged(QAbstractSocket::SocketState state)
      {
          switch(state)
          {
          case QAbstractSocket::UnconnectedState:
              lblSocketState->setText("socket状态:UnconnectedState");
              break;
          case QAbstractSocket::HostLookupState:
              lblSocketState->setText("socket状态:HostLookupState");
              break;
          case QAbstractSocket::ConnectingState:
              lblSocketState->setText("socket状态:ConnectingState");
              break;
          case QAbstractSocket::ConnectedState:
              lblSocketState->setText("socket状态:ConnectedState");
              break;
          case QAbstractSocket::BoundState:
              lblSocketState->setText("socket状态:BoundState");
              break;
          case QAbstractSocket::ClosingState:
              lblSocketState->setText("socket状态:ClosingState");
              break;
          case QAbstractSocket::ListeningState:
              lblSocketState->setText("socket状态:ListeningState");
              break;
          }
      }
  • 客户端向服务端发送数据:Socket之间的数据通信协议一般有两种方式,基于行的或基于数据块的;基于行的数据通信协议一般用于纯文本数据的通信,每一行数据以一个换行符结束。基于数据块的数据通信协议用于一般的二进制数据的传输,需要自定义数据的格式。下面为客户端向服务器发送数据的代码:

      void MainWindow::on_btnSend_clicked()
      {
          QString msg=ui->txtSend->text();
          ui->plainTextEdit->appendPlainText("[out] "+msg);
          ui->txtSend->clear();
          ui->txtSend->setFocus();
          QByteArray str=msg.toUtf8();
          str.append('\n');
          tcpSocket->write(str);
      }
  • 当服务器向客户端发送数据的时候,客户端收到数据会触发readyRead()信号,对应的槽函数代码如下:

      void MainWindow::onSocketReadyRead()
      {
          while(tcpSocket->canReadLine())
          {
              ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
          }
      }
  • 断开与服务器的连接代码如下:

      void MainWindow::on_actDisconnect_triggered()
      {
          if(tcpSocket->state()==QAbstractSocket::ConnectedState)
          {
              tcpSocket->disconnectFromHost();//断开连接
          }
      }

TCP Server编程

  • TCP Server Demo的界面设计如下:
    729394-20190910104107449-1571635885.jpg

  • 初始化服务器对象,添加有新的客户端接入的信号与槽。

      tcpServer=new QTcpServer(this);
      connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));//添加tcp客户端连接上发送信号newConnection和对应的槽函数关联
  • 开启服务监听代码如下:

      void MainWindow::on_actListenning_triggered()
      {
          QString ip=ui->cbbxListenAdd->currentText();//IP地址
          quint16 port=ui->spbxPort->value();//端口号
          QHostAddress add(ip);
          tcpServer->listen(add,port);
          ui->plainTextEdit->appendPlainText("**开始监听。。");
          ui->plainTextEdit->appendPlainText("**服务器地址:"+tcpServer->serverAddress().toString());
          ui->plainTextEdit->appendPlainText("服务器端口号:"+QString::number(tcpServer->serverPort()));
          ui->actListenning->setEnabled(false);
          ui->actStopListening->setEnabled(true);
          lblListeningState->setText("监听状态:正在监听");
      }
  • 当有新客户端连接上时触发的槽函数

      //新用户连接上触发的槽函数
      void MainWindow::onNewConnection()
      {
          tcpSocket=tcpServer->nextPendingConnection();//获取新连接上的tcp客户端Socket对象
    
          //添加信号已连接的信号与槽
          connect(tcpSocket,SIGNAL(connected()),this,SLOT(onClientConnected()));
          onClientConnected();
    
          //添加客户端与服务器断开的信号与槽
          connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(onClientDisconnected()));
    
          //添加连接的socket状态变化的信号与槽
          connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
          onSocketStateChanged(tcpSocket->state());
    
          //添加有数据到达的信号与槽
          connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
    
      }
  • 客户端连接上服务器触发的槽函数如下:

      void MainWindow::onClientConnected()
      {
          ui->plainTextEdit->appendPlainText("客户端socket已经连接");
          ui->plainTextEdit->appendPlainText("客户端地址:"+tcpSocket->peerAddress().toString());
          ui->plainTextEdit->appendPlainText("客户端端口号:"+QString::number(tcpSocket->peerPort()));
      }
  • Socket状态发生变化的槽函数如下:

      void MainWindow::onSocketStateChanged(QAbstractSocket::SocketState socketState)
      {
          switch(socketState)
          {
          case QAbstractSocket::UnconnectedState:
              lblSocketState->setText("socket状态:UnconnectedState");
              break;
          case QAbstractSocket::HostLookupState:
              lblSocketState->setText("socket状态:HostLookupState");
              break;
          case QAbstractSocket::ConnectingState:
              lblSocketState->setText("socket状态:ConnectingState");
              break;
          case QAbstractSocket::ConnectedState:
              lblSocketState->setText("socket状态:ConnectedState");
              break;
          case QAbstractSocket::BoundState:
              lblSocketState->setText("socket状态:BoundState");
              break;
          case QAbstractSocket::ClosingState:
              lblSocketState->setText("socket状态:ClosingState");
              break;
          case QAbstractSocket::ListeningState:
              lblSocketState->setText("socket状态:ListeningState");
              break;
          }
      }
  • 客户端断开了与服务端的链接触发的槽函数如下:

      void MainWindow::onClientDisconnected()
      {
          ui->plainTextEdit->appendPlainText("客户端已经断开连接");
          tcpSocket->deleteLater();
      }
  • 服务端向客户端发送数据的代码如下:

      //消息发送
      //socket数据之间的数据通信协议一般有两种,基于行或者基于数据块
      //基于行的通信一般用于纯文本通信
      void MainWindow::on_btnSend_clicked()
      {
          QString msg=ui->txtSend->text();
          ui->plainTextEdit->appendPlainText("[out] "+msg);
          ui->txtSend->clear();
          ui->txtSend->setFocus();
    
          QByteArray str=msg.toUtf8();
          str.append('\n');
          tcpSocket->write(str);
      }
  • 服务端收到客户端数据槽函数代码如下:

      void MainWindow::onSocketReadyRead()
      {
          while(tcpSocket->canReadLine())
          {
              ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
          }
      }
  • 关闭服务端监听代码如下:

      void MainWindow::on_actStopListening_triggered()
      {
          if(tcpServer->isListening())//如果正在监听
          {
              tcpServer->close();
              ui->actListenning->setEnabled(true);
              ui->actStopListening->setEnabled(false);
              lblListeningState->setText("监听状态:停止监听");
          }
      }

UDP编程

  • 用户数据报协议(UDP)是轻量的,不可靠的,面向数据报,无链接的协议,他可以用于对可靠性要求不搞的场合,与TCP通信不同,两个程序之间进行UDP通信无需建立持久的socket连接,UDP每次发送数据包都需要指定目标地址和端口。
  • QUdpSocket以数据包传输数据,而不是以连续的字节流;发送数据包使用函数QUdpSocket::writeDatagram(),数据包的长度一般少于512字节,每个数据包包含发送和接收者的IP地址和端口等信息。
  • 要进行UDP数据接收,要用QUdpSocket::bind()函数先绑定一个端口,用于接收传入的数据,当有数据传入时,会发射readyRead()信号,使用readDataGgram()函数来读取接收到的数据报。
  • UDP消息传播有单播,广播,组播三种模式。
  • 单播模式:一个UDP客户端发出的数据报只发送到另一个指定的地址和端口号的UDP客户端,是一对一的数据传输。
  • 广播模式:一个UDP客户端发出的数据报,在同一网络范围内其它所有的UDP客户端都可以接收到;要获取广播数据只需要在数据报中指定接收端地址为QHostAddress::Broadcast.一般的广播地址是255.255.255.255
  • 组播模式:也成称为多播。UDP客户端加入到一个组播IP地址指定的多播组,成员向组播地址发送的数据报组内成员都可以接收到,类似QQ群的功能。QUdpSocket::joinMulticastGroup()函数实现加入多播组的功能,加入多播组后,UDP数据的收发与正常的UDP数据收发方法是一样的。

    UDP单播和广播demo

  • 界面设计如下:
    729394-20190910104124897-1733744298.jpg

  • 绑定端口代码如下:

      //绑定端口
      void MainWindow::on_actBundPort_triggered()
      {
          quint16 localPort=ui->spbBindPort->value();
          if(udpSocket->bind(localPort))//如果端口绑定成功
          {
              ui->plainTextEdit->appendPlainText("**已成功绑定");
              ui->plainTextEdit->appendPlainText("**绑定端口:"+QString::number(udpSocket->localPort()));
              ui->actBundPort->setEnabled(false);
              ui->actDisBund->setEnabled(true);
          }
          else
          {
              ui->plainTextEdit->appendPlainText("**绑定失败");
          }
      }
  • 单播发送消息代码如下:

      //发送消息
      void MainWindow::on_btnSend_clicked()
      {
          //目标IP地址
          QString aimIP=ui->cbbxAimAddress->currentText();
          //目标计算机Host地址
          QHostAddress aAddress(aimIP);
          //目标端口号
          quint16 port=ui->spbAimPort->value();
          QString msg=ui->txtSend->text();
          //字符串转QByteArray
          QByteArray str=msg.toUtf8();
          //单播发送数据包
          udpSocket->writeDatagram(str,aAddress,port);//发送数据包,一般数据包的长度最大不超过512字节
          ui->plainTextEdit->appendPlainText("[out] "+msg);
          ui->txtSend->clear();
          ui->txtSend->setFocus();
      }
  • 广播发送消息,广播消息的时候需要将目标地址更换为特殊的地址,即广播地址:QHostAddress::Broadcast一般为255.255.255.255,广播发送消息代码如下:

      //广播消息
      void MainWindow::on_btnBoardcast_clicked()
      {
          quint16 aimPort=ui->spbAimPort->value();
          QString msg=ui->txtSend->text();
          QByteArray str=msg.toUtf8();
          udpSocket->writeDatagram(str,QHostAddress::Broadcast,aimPort);
          ui->plainTextEdit->appendPlainText("[boardcast] "+msg);
          ui->txtSend->clear();
          ui->txtSend->setFocus();
      }
  • 读取数据报数据代码如下:

      //读取数据报数据
      void MainWindow::onSocketReadyRead()
      {
          while(udpSocket->hasPendingDatagrams())
          {
              QByteArray datagram;
              datagram.resize(udpSocket->pendingDatagramSize());
              QHostAddress peerAddress;
              quint16 peerPort;
              udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddress,&peerPort);
              QString str=datagram.data();
              QString peer="[from "+peerAddress.toString()+QString::number(peerPort)+"] ";
              ui->plainTextEdit->appendPlainText(peer+str);
          }
      }
  • UDP解除绑定的端口号代码如下:

      void MainWindow::on_actDisBund_triggered()
      {
          udpSocket->abort();
          ui->actBundPort->setEnabled(true);
          ui->actDisBund->setEnabled(false);
          ui->plainTextEdit->appendPlainText("**已解除绑定");
      }

UDP组播

  • 采用UDP组播必须使用一个组播地址,组播地址是D类IP地址,关于组播地址有如下的一下约定,如下图所示:
    729394-20190910104144697-489085024.jpg

  • UDP组播 Demo界面设计如下图所示:
    729394-20190910104156032-2143852391.jpg

  • 组播UDP的初始化,代码如下:

      udpSocket=new QUdpSocket(this);
      udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);//MulticastTtlOption为组播数据报的生存周期,数据报每夸一个路由会减1;缺省值为1表示多播数据报只能在同一路由的局域网内传播
  • 加入组播代码:

      //加入组播槽函数
      void MainWindow::on_actAddMulticast_triggered()
      {
          QString ip=ui->cbbxMulticastAddr->currentText();
          groupAddress=QHostAddress(ip);//组播地址
          quint16 groupPort=ui->spbPort->value();
          if(udpSocket->bind(QHostAddress::AnyIPv4,groupPort,QUdpSocket::ShareAddress))//绑定端口
          {
              udpSocket->joinMulticastGroup(groupAddress);
              ui->plainTextEdit->appendPlainText("加入组播成功!");
              ui->plainTextEdit->appendPlainText("组播地址IP:"+ip);
              ui->plainTextEdit->appendPlainText("**绑定的端口:"+QString::number(groupPort));
              ui->actAddMulticast->setEnabled(false);
              ui->actExitMulticast->setEnabled(true);
              ui->cbbxMulticastAddr->setEnabled(false);
          }
          else
          {
              ui->plainTextEdit->appendPlainText("绑定端口失败!");
          }
    
      }
  • 退出组播代码如下:

      //退出组播槽函数
      void MainWindow::on_actExitMulticast_triggered()
      {
          udpSocket->leaveMulticastGroup(groupAddress);//退出组播
          udpSocket->abort();//解除绑定
          ui->actAddMulticast->setEnabled(true);
          ui->actExitMulticast->setEnabled(false);
          ui->cbbxMulticastAddr->setEnabled(true);
          ui->plainTextEdit->appendPlainText("**已退出组播,解除端口绑定");
      }
  • 其它接收发消息和广播收发消息一致。

    其它网络编程如Http,FTP,SNMP QT也都是支持的

  • 主要会用到QNetworkRequest、QNetworkReply和QNetworkAccessManager这些类

转载于:https://www.cnblogs.com/deng-c-q/p/11496082.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值