• QT网络编程


    QT网络编程

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

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

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

    QHostInfoQNetWorkInterface获取网络信息demo

    • 界面设计

    • 获取主机按钮槽函数

        //获取主机信息按钮事件
        void MainWindow::on_btn_host_clicked()
        {
        	//hostinfo获取主机的信息
        	QString hostName=QHostInfo::localHostName();//获取本机的主机名
        	ui->plainTextEdit->appendPlainText("主机名为:"+hostName+"
      ");
      
        	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()+"
      ");
        		}
        		ui->plainTextEdit->appendPlainText("
      ");
        	}
        }  
      

    Qt TCP编程

    TCP Client编程

    • TCP Client客户端界面如下图:

    • 连接服务器

        //连接服务器
        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('
      ');
        	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的界面设计如下:

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

        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('
      ');
        	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

    • 界面设计如下:

    • 绑定端口代码如下:

        //绑定端口
        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地址,关于组播地址有如下的一下约定,如下图所示:

    • UDP组播 Demo界面设计如下图所示:

    • 组播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这些类
  • 相关阅读:
    【简单易懂】JPA概念解析:CascadeType(各种级联操作)详解
    [转] @JoinColumn 详解 (javax.persistence.JoinColumn)
    Feign二: @FeignClient 接口调用
    @Basic表示一个简单的属性 懒加载,急加载
    RPC接口测试(一)什么是 RPC 框架
    Mysql中 查询慢的 Sql语句的记录查找
    Mysql 查看连接数,状态 最大并发数
    ntp时间一致对与设备心跳的影响
    jmeter常用四种断言
    jmeter BeanShell断言(四)
  • 原文地址:https://www.cnblogs.com/deng-c-q/p/11496082.html
Copyright © 2020-2023  润新知