14-1_Qt 5.9 C++开发指南_网络编程及主机信息查询_HostInfo

Qt 网络模块提供了用于编写 TCP/IP 客户端和服务器端程序的各种类,如用于 TCP 通信的QTcpSocket 和 QTcpServer,用于 UDP 通信的 QUdpSocket,还有用于实现 HTTP、FTP 等普通网络协议的高级类如 QNetworkRequest,QNetworkReply 和QNetworkAccessManager。Qt 网络模块还提供用于网络代理、网络承载管理的类,提供基于安全套接字层 (Secure Sockets Layer,SSL)协议的安全网络通信的类。

本章主要介绍基本的 TCP 和 UDP 网络通信类的使用,基于 HTTP 的网络下载管理的实现。

要在程序中使用 Qt 网络模块,需要在项目配置文件中增加一条配置语句:
Qt+= network

文章目录

  • 1. QHostInfo 和 QNetworkInterface 类
  • 2.可视化UI设计框架
  • 3. QHostInfo的使用
    • 3.1 显示本机地址信息
    • 3.2 查找主机地址信息
  • 4. QNetworkInterface 的使用
  • 5. 源码
    • 5.1 dialog.h
    • 5.2 dialog.cpp

1. QHostInfo 和 QNetworkInterface 类

查询一个主机的MAC地址或IP 地址是网络应用程序中经常用到的功能,Qt提供了QHostInfo和QNetworkInterface 类可以用于此类信息的查询。

QHostInfo 的静态函数 localHostName()可获取本机的主机名,静态函数 fromName()可以通过主机名获取 IP 地址,静态函数 lookupHost()可以通过一个主机名,以异步方式查找这个主机的 IP地址。表14-1 是QHostInfo 类主要的功能函数(省略了函数中的 const 关键字)。
在这里插入图片描述
QNetworkInterface 可以获得运行应用程序的主机的所有 IP 地址和网络接口列表。静态函数alInterfaces()返回主机上所有的网络接口的列表,一个网络接口可能包括多个的 IP 地址,每个IP地址与掩码或广播地址关联。如果无需知道子网掩码和广播的IP 地址,使用静态函数 allAddresses()可以获得主机上的所有IP 地址列表。表 14-2是 QNetworkInterface 类的主要功能函数。
在这里插入图片描述

为演示这两个类的主要功能,创建一个窗口基于 QDialog 的应用程序 samp14_1,实例运行时界面如图 14-1 所示。对话框界面由 UI设计器设计,主要代码都是各按钮的 clicked()信号的槽函数。

在这里插入图片描述

2.可视化UI设计框架

在这里插入图片描述

3. QHostInfo的使用

3.1 显示本机地址信息

图 14-1 窗口上的“QHostInfo 获取本机主机名和IP 地址”按钮的响应代码如下:

void Dialog::on_btnGetHostInfo_clicked()
{//QHostInfo获取主机信息
//    ui->plainTextEdit->clear();QString hostName=QHostInfo::localHostName();//本地主机名ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n");QHostInfo   hostInfo=QHostInfo::fromName(hostName); //本机IP地址QList<QHostAddress> addList=hostInfo.addresses();//IP地址列表if (!addList.isEmpty())for (int i=0;i<addList.count();i++){QHostAddress aHost=addList.at(i); //每一项是一个QHostAddressbool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4if (show)show=(QAbstractSocket::IPv4Protocol==aHost.protocol()); //协议类型,elseshow=true;if (show) {ui->plainTextEdit->appendPlainText("协 议:"+protocolName(aHost.protocol()));//协议类型ui->plainTextEdit->appendPlainText("本机IP地址:"+aHost.toString()); //IP地址ui->plainTextEdit->appendPlainText("");}}
}

这段代码先通过静态函数QHostInfo::localHostName()获取本机主机名hostName,然后再使用主机名作为参数,用静态函数QHostInfo::fromName(hostName)获取主机的信息 hostInfo。

hostInfo 是 QHostInfo 类的实例,通过其函数addresses()获取主机的IP 地址列表。

QList<QHostAddress> addList=hostInfo.addresses();//IP地址列表

返回的addList是QHostAddress 类的列表,QHostAddress 类提供一个IP 地址的信息,包括IPv4地址和IPv6 地址。QHostAddress 有以下两个主要的函数。

  • protocol() 返回 QAbstractSocket::NetworkLayerProtocol类型变量,表示当前IP 地址的协议类型。QAbstractSocket::NetworkLayerProtocol枚举类型的取值见表14-3。
    在这里插入图片描述

  • toString()返回IP 地址的字符串,表示程序中显示了IP 地址列表中每个IP 地址的协议类型和IP 地址字符串,为根据 protocol()返回的 QAbstractSocket::NetworkLayerProtocol 枚举值显示协议名称字符串,自定义了一个函数 protocolName(),代码如下:

QString Dialog::protocolName(QAbstractSocket::NetworkLayerProtocol protocol)
{//通过协议类型返回协议名称switch(protocol){case QAbstractSocket::IPv4Protocol:return "IPv4 Protocol";case QAbstractSocket::IPv6Protocol:return "IPv6 Protocol";case QAbstractSocket::AnyIPProtocol:return "Any IP Protocol";default:return "Unknown Network Layer Protocol";}
}

单击“QHostInfo 获取本机主机名和 IP 地址”按钮,如果勾选了“只显示 IPv4 协议地址”复选框,就只显示本机的 IPv4 地址,否则显示所有 IP 地址信息。

3.2 查找主机地址信息

QHostInfo 的静态函数 lookupHost()可以根据主机名、域名或 IP 地址查找主机的地址信息,lookupHost()函数原型如下:

[static] int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member)

输入参数 name 是表示主机名的字符串,可以是一个主机名、一个域名,或者是一个IP 地址。

lookupHost()以异步方式查找主机地址,参数 receiver 和 member 指定一个响应槽函数的接收者和槽函数名称。执行 lookupHost()后,程序可能需要花一定时间来查找主机地址,但不会阻塞程序的运行。当查找到主机地址后,通过信号通知设定的槽函数,在槽函数里读取查找的结果。函数返回一个表示查找的 ID。
图14-1 中的“QHostInfo 查找域名的IP 地址”按的槽函数及 lokupHost()函数关联槽函数代码如下:

void Dialog::on_btnLookup_clicked()
{//查找主机信息QString hostname=ui->editHost->text(); //主机名ui->plainTextEdit->appendPlainText("正在查找查找主机信息:"+hostname);QHostInfo::lookupHost(hostname,this,SLOT(lookedUpHostInfo(QHostInfo)));
}void Dialog::lookedUpHostInfo(const QHostInfo &host)
{//查找主机信息的槽函数
//    ui->plainTextEdit->clear();QList<QHostAddress> addList=host.addresses();//if (!addList.isEmpty())for (int i=0;i<addList.count();i++){QHostAddress aHost=addList.at(i);bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4if (show)show=QAbstractSocket::IPv4Protocol==aHost.protocol();elseshow=true;if (show) {ui->plainTextEdit->appendPlainText("协 议:"+protocolName(aHost.protocol()));ui->plainTextEdit->appendPlainText(aHost.toString());}}
}

运行结果如下图:
在这里插入图片描述

4. QNetworkInterface 的使用

QNetworkInterface 可以获得应用程序所在主机的所有网络接口,包括其子网掩码和广播地址等。

静态函数QNetworkInterface::allInterfaces()获取所有网络接口的列表,函数原型为:

[static] [QList](../qtcore/qlist.html)<[QNetworkInterface](qnetworkinterface.html#QNetworkInterface)> QNetworkInterface::allInterfaces()

其返回结果是一个QNetworkInterface 类的列表。

界面上“QNetworkInterface::allInterfaces()”按钮的响应代码如下:

void Dialog::on_btnALLInterface_clicked()
{//QNetworkInterface::allInterfaces()函数的使用
//    ui->plainTextEdit->clear();QList<QNetworkInterface>    list=QNetworkInterface::allInterfaces();for(int i=0;i<list.count();i++){QNetworkInterface aInterface=list.at(i);if (!aInterface.isValid())continue;ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("设备名称:")+aInterface.humanReadableName());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("硬件地址:")+aInterface.hardwareAddress());QList<QNetworkAddressEntry> entryList=aInterface.addressEntries();for(int j=0;j<entryList.count();j++){QNetworkAddressEntry aEntry=entryList.at(j);ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   IP 地址:")+aEntry.ip().toString());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   子网掩码:")+aEntry.netmask().toString());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   广播地址:")+aEntry.broadcast().toString()+"\n");}ui->plainTextEdit->appendPlainText("\n");}
}

通过QNetworkInterface::allInterfaces()获取网络接口列表 list之后,显示每个接口的 humanReadableName()和 hardwareAddress()。每个接口又有一个 QNetworkAddressEntry 类型的地址列表,通过addressEntries ()获得这个列表。
QNetworkAddressEntry 包含了一个网络接口的 IP 地址、子网掩码和广播地址,分别用 ip()、netmask()和 broadcast()函数返回。
QNetworkInterface::allInterfaces()返回的网络接口的信息很多,如果无需知道子网掩码和广播地址等信息,可以使用 QNetworkInterface::allAddresses()只获取IP 地址。

界面上“QNetworkInterface ::allAddresses()”按钮的响应代码如下:

void Dialog::on_btnDetail_clicked()
{//QNetworkInterface::allAddresses()的使用
//    ui->plainTextEdit->clear();QList<QHostAddress> addList=QNetworkInterface::allAddresses();//if (!addList.isEmpty())for (int i=0;i<addList.count();i++){QHostAddress aHost=addList.at(i);bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4if (show)show=QAbstractSocket::IPv4Protocol==aHost.protocol();elseshow=true;if (show){ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协  议:")+protocolName(aHost.protocol()));ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("IP地址:")+aHost.toString());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(""));}}
}

QNetworkInterface ::allAddresses()的功能与 QHstInfo:addresses()函数功能相似,都是返回-个QHostAddress 的列表。只是 QNetworkInterface 会返回更多地址,包括表示本机的 127.0.0.1,而QHostInfo 不会返回这个IP 地址。

5. 源码

5.1 dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include    <QDialog>
#include    <QHostInfo>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{Q_OBJECTpublic:explicit Dialog(QWidget *parent = 0);~Dialog();private slots:void lookedUpHostInfo(const QHostInfo &host);//===========================void on_btnGetHostInfo_clicked();void on_btnDetail_clicked();void on_btnLookup_clicked();void on_btnALLInterface_clicked();void on_btnClear_clicked();private:Ui::Dialog *ui;QString  protocolName(QAbstractSocket::NetworkLayerProtocol protocol);
};#endif // DIALOG_H

5.2 dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"#include    <QHostInfo>
#include    <QNetworkInterface>Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{ui->setupUi(this);
}Dialog::~Dialog()
{delete ui;
}void Dialog::lookedUpHostInfo(const QHostInfo &host)
{//查找主机信息的槽函数
//    ui->plainTextEdit->clear();QList<QHostAddress> addList=host.addresses();//if (!addList.isEmpty())for (int i=0;i<addList.count();i++){QHostAddress aHost=addList.at(i);bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4if (show)show=QAbstractSocket::IPv4Protocol==aHost.protocol();elseshow=true;if (show) {ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协 议:")+protocolName(aHost.protocol()));ui->plainTextEdit->appendPlainText(aHost.toString());}}
}void Dialog::on_btnGetHostInfo_clicked()
{//QHostInfo获取主机信息
//    ui->plainTextEdit->clear();QString hostName=QHostInfo::localHostName();//本地主机名ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("本机主机名:")+hostName+"\n");QHostInfo   hostInfo=QHostInfo::fromName(hostName); //本机IP地址QList<QHostAddress> addList=hostInfo.addresses();//IP地址列表if (!addList.isEmpty())for (int i=0;i<addList.count();i++){QHostAddress aHost=addList.at(i); //每一项是一个QHostAddressbool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4if (show)show=(QAbstractSocket::IPv4Protocol==aHost.protocol()); //协议类型,elseshow=true;if (show) {ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协 议:")+protocolName(aHost.protocol()));//协议类型ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("本机IP地址:")+aHost.toString()); //IP地址ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(""));}}
}void Dialog::on_btnDetail_clicked()
{//QNetworkInterface::allAddresses()的使用
//    ui->plainTextEdit->clear();QList<QHostAddress> addList=QNetworkInterface::allAddresses();//if (!addList.isEmpty())for (int i=0;i<addList.count();i++){QHostAddress aHost=addList.at(i);bool show=ui->chkOnlyIPv4->isChecked();//只显示IPv4if (show)show=QAbstractSocket::IPv4Protocol==aHost.protocol();elseshow=true;if (show){ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("协  议:")+protocolName(aHost.protocol()));ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("IP地址:")+aHost.toString());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(""));}}
}void Dialog::on_btnLookup_clicked()
{//查找主机信息QString hostname=ui->editHost->text(); //主机名ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("正在查找查找主机信息:")+hostname);QHostInfo::lookupHost(hostname,this,SLOT(lookedUpHostInfo(QHostInfo)));
}void Dialog::on_btnALLInterface_clicked()
{//QNetworkInterface::allInterfaces()函数的使用
//    ui->plainTextEdit->clear();QList<QNetworkInterface>    list=QNetworkInterface::allInterfaces();for(int i=0;i<list.count();i++){QNetworkInterface aInterface=list.at(i);if (!aInterface.isValid())continue;ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("设备名称:")+aInterface.humanReadableName());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("硬件地址:")+aInterface.hardwareAddress());QList<QNetworkAddressEntry> entryList=aInterface.addressEntries();for(int j=0;j<entryList.count();j++){QNetworkAddressEntry aEntry=entryList.at(j);ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   IP 地址:")+aEntry.ip().toString());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   子网掩码:")+aEntry.netmask().toString());ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("   广播地址:")+aEntry.broadcast().toString()+"\n");}ui->plainTextEdit->appendPlainText("\n");}
}QString Dialog::protocolName(QAbstractSocket::NetworkLayerProtocol protocol)
{//通过协议类型返回协议名称switch(protocol){case QAbstractSocket::IPv4Protocol:return "IPv4 Protocol";case QAbstractSocket::IPv6Protocol:return "IPv6 Protocol";case QAbstractSocket::AnyIPProtocol:return "Any IP Protocol";default:return "Unknown Network Layer Protocol";}
}void Dialog::on_btnClear_clicked()
{ui->plainTextEdit->clear();
}

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

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

相关文章

SpringBoot 入门

0目录 1.SpringBoot简介&#xff1b;优点和目录结构 2.实战 3.YML基本语法 4.集成Mybatis 1.SpringBoot简介&#xff1b;优点和目录结构 2.实战 创建工程 去s 降低错误率&#xff0c;更改地址 选择Maven 组和名称 修改版本&#xff0c;加入依赖 新建controller …

f12 CSS网页调试_css样式被划了黑线怎么办

我的问题是这样的 class加上去了,但是样式不生效,此时可能是样式被其他样式覆盖了, 解决方案就是 给颜色后边添加一个!important

Python 进阶(三):正则表达式(re 模块)

❤️ 博客主页:水滴技术 🌸 订阅专栏:Python 入门核心技术 🚀 支持水滴:点赞👍 + 收藏⭐ + 留言💬 文章目录 1. 导入re模块2. re模块中的常用函数2.1 re.search()2.2 re.findall()2.3 re.sub()2.4 re.compile()2.5 re.split()3. 正则表达式的语法4. 匹配对象的属性和

淘宝资源采集(从零开始学习淘宝数据爬取)

1. 为什么要进行淘宝数据爬取&#xff1f; 淘宝数据爬取是指通过自动化程序从淘宝网站上获取数据的过程。这些数据可以包括商品信息、销售数据、评论等等。淘宝数据爬取可以帮助您了解市场趋势、优化您的产品选择以及提高销售额。 淘宝作为全球的电商平台&#xff0c;每天都有…

jmeter中json提取器,获取多个值,并通过beanshell组成数组

jmeter中json提取器介绍 特别说明&#xff1a;**Compute concatenation var(suffix_ALL)&#x1f617;*如果找到许多结果&#xff0c;则插件将使用’ &#xff0c; 分隔符将它们连接起来&#xff0c;并将其存储在名为 _ALL的var中 json提取器调试 在查看结果树中选择JSON Pat…

FSM:Full Surround Monodepth from Multiple Cameras

参考代码&#xff1a;None 介绍 深度估计任务作为基础环境感知任务&#xff0c;在基础上构建的3D感知才能更加准确&#xff0c;并且泛化能力更强。单目的自监督深度估计已经有MonoDepth、ManyDepth这些经典深度估计模型了&#xff0c;而这篇文章是对多目自监督深度估计进行探…

JavaEE 面试常见问题

一、常见的 ORM 框架有哪些&#xff1f; 1.Mybatis Mybatis 是一种典型的半自动的 ORM 框架&#xff0c;所谓的半自动&#xff0c;是因为还需要手动的写 SQL 语句&#xff0c;再由框架根据 SQL 及 传入数据来组装为要执行的 SQL 。其优点为&#xff1a; 1. 因为由程序员…

使用vs 2017 C#项目发布

C#项目发布 vs 2017 打包项目源代码 (发布)iis 配置添加ssl 配置 vs 2017 打包项目源代码 (发布) iis 配置 添加ssl 配置 https://help.aliyun.com/zh/ssl-certificate/user-guide/install-ssl-certificates-on-iis-servers

Python+PIL计算两个图像的相似度并返回第一个不匹配的像素的x坐标(附完整版代码)

前言 前几天看到一篇文章写Pythonselenium超级鹰对滑块验证码的操作&#xff0c;大致的思想如下&#xff1a; 1、就是将滑块验证码进行截图 2、利用超级鹰的API进行对图片的处理&#xff0c; 3、返回滑块的距离 我在很久之前也遇到过类似的需求&#xff0c; 当时我的好友帮我写…

React之组件的生命周期

React之组件的生命周期 一、概述二、整体说明三、挂载阶段四、更新阶段五、卸载阶段 一、概述 生命周期:一个事务从创建到最后消亡经历的整个过程组件的生命周期&#xff1a;组件从被创建到挂载到页面中运行&#xff0c;再到组件不用时卸载的过程意义&#xff1a;理解组件的生…

Docker Dockerfile 语法与指令

一、简介 Docker 镜像原理、容器转成镜像 随便找个案例&#xff0c;进入 https://hub.docker.com/ 搜索 centos&#xff0c;然后随便找个版本&#xff08;例如&#xff1a;centos7&#xff09;点击一下&#xff0c;就会进入 centos7 的 dockerfile 文件&#xff1a; // 空镜像…

MTK system_server 卡死导致手机重启案例分析

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、MTK AEE Log分析工具二、AEE Log分析流程三、system_server 卡死案例分析及解决 本文主要针对 Exception Type: system_server_watchdog , system_…

postgis mvt矢量切片 django drf mapboxgl

postgis mvt矢量切片 django drf mapboxgl 目录 0.前提 1.sql代码 2.django drf后端服务代码 3.具体的应用&#xff08;整体代码&#xff09; 4.参考 0.前提 [1] 静态的矢量切片可以采用 tippecanoe 生成&#xff0c;nginx代理&#xff0c;这种数据是不更新的&#xff1b…

C++ 第六弹 STL

目录 1.什么是stl 2.六大组件-容器-序列式容器-C98 string 3.六大组件-容器-序列式容器-C98 vector 4.六大组件-容器-序列式容器-C98 list 5.六大组件-容器-序列式容器-C98 deque 6.六大组件-容器-序列式容器-C11 array 7.六大组件-容器-序列式容器-C11 forward_list 8…

RT1052 的周期定时器

文章目录 1 PIT 周期中断定时器2 PIT定时器的使用3 PIT定时器配置3.1 PIT 时钟使能。3.1.1 CLOCK_EnableClock 3.2 初始化 PIT 定时器3.2.1 PIT_Init 3.3 设置 通道 0 的 加载值3.3.1 PIT_SetTimerPeriod 3.4 使能 通道 0 的中断3.4.1 PIT_EnableInterrupts 3.5 开启 PIT 定时器…

NetSuite ERP顾问的进阶之路

目录 1.修养篇 1.1“道”是什么&#xff1f;“器”是什么&#xff1f; 1.2 读书这件事儿 1.3 十年计划的力量 1.3.1 一日三省 1.3.2 顾问损益表 1.3.3 阶段课题 2.行为篇 2.1协作 2.2交流 2.3文档管理 2.4时间管理 3.成长篇 3.1概念能力 3.1.1顾问的知识结构 …

word转pdf怎么转?几种常用方法分享

word转pdf怎么转&#xff1f;在日常工作和学习中&#xff0c;将Word文档转换为PDF格式是一项必要的任务。不仅可以保证文档的格式不变&#xff0c;还可以防止文档被他人篡改。但是&#xff0c;Word文档并不是所有人都能够轻松打开和编辑的&#xff0c;而PDF文件则可以在各种设备…

使用DataX实现mysql与hive数据互相导入导出

一、概论 1.1 什么是DataX DataX 是阿里巴巴开源的一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle 等)、HDFS、Hive、ODPS、HBase、FTP 等各种异构数据源之间稳定高效的数据同步功能。 1.2 DataX 的设计 为了解决异构数据源同步问题&#xf…

安全学习DAY09_加密逆向,特征识别

算法逆向&加密算法分类&#xff0c;特征识别 文章目录 算法逆向&加密算法分类&#xff0c;特征识别算法概念&#xff0c;分类单向散列加密 - MD5对称加密 - AES非对称加密 - RSA 常见加密算法识别特征&#xff0c;解密特点MD5密文特点BASE64编码特点AES、DES特点RSA密文…

Vue实现leafletMap自定义绘制线段 并且删除指定的已绘制的点位

效果&#xff1a;点击表格可实现选中地图点位&#xff0c;删除按钮点击可删除对应点位并且重新绘制线段&#xff0c;点击确定按钮 保存已经绘制的点位信息传给父组件 并且该组件已实现回显 完整的组件代码如下 文件名称为&#xff1a; leafletMakePointYt <!--* Descripti…