Linux——匿名管道

Linux——匿名管道

  • 什么是管道
  • 匿名管道的底层原理
  • 观察匿名管道现象
    • 读写端的几种情况
    • 写端慢,读端快
    • 写端快,读端慢
  • 管道的大小
    • 写端关闭,读端一直读
    • 写端一直写,读端关闭

我们之前一直用的是vim来编写代码,现在有了vscode这样强大的编辑器,我们可以把我们的vim放一边了,如果还有小伙伴还没有配置好vscode的远端,可以点击这里:

https://blog.csdn.net/qq_67693066/article/details/136368891

我们今天进入管道的学习:

什么是管道

在计算机领域,管道(Pipeline)是一种将多个命令连接在一起以形成数据流的机制。它允许一个命令的输出成为另一个命令的输入,从而实现命令之间的数据传递和处理。

在 Unix/Linux 系统中,管道通常用竖线符号 | 表示。通过管道,可以将一个命令的输出传递给另一个命令进行处理,从而构建复杂的数据处理流程。

例如,假设我们有两个命令 command1 和 command2,我们可以使用管道将它们连接起来:

command1 | command2

这将会把 command1 的输出作为 command2 的输入,command2 将处理 command1 的输出并生成最终的结果。

管道的优势包括:

简化复杂任务: 管道可以将多个简单的命令组合成一个复杂的任务,使得任务的实现更加简单和高效。
模块化和可重用性: 通过将命令连接在一起,可以更好地组织代码并提高代码的可重用性。每个命令都可以专注于完成一个特定的任务。
减少临时文件: 管道可以避免将数据存储到临时文件中,从而减少了文件 I/O 的开销和磁盘空间的占用。
实时处理: 管道允许命令之间的实时数据传递,这对于需要连续处理数据的任务非常有用,比如日志处理、数据流分析等。

简单来说,管道就是连接多个指令。我们之前也在频繁使用管道:比如我们想统计当前登录到系统的用户数量。
在这里插入图片描述
who指令的结果作为wc -l的输入。

匿名管道的底层原理

我们这里讲的简单一点,现在我们有一个进程,它自身会被以读和写的方式分别打开一次:
在这里插入图片描述
然后这个读和写都会往一个缓冲区输入输出数据:

这个时候父进程创建子进程,子进程发生浅拷贝,指向没有发生变化:
在这里插入图片描述
这里注意一下,管道一般是单向的,所以我们现在想让父进程读,让子进程写
在这里插入图片描述
这样形成了一个单向通道,这个就是一个基本的匿名管道

匿名管道(Anonymous Pipe)是一种用于进程间通信的机制,特别是在 Unix 和类 Unix 系统中。它允许一个进程将输出发送到另一个进程的输入,从而实现进程间的数据传输。
以下是匿名管道的一些关键特点:
单向通信:匿名管道是单向的,只能支持单向数据流。它只能用于单一方向的通信,通常是父进程到子进程或者相反。
创建:匿名管道通过调用系统调用 pipe() 来创建。这个系统调用创建了一个管道,返回两个文件描述符,其中一个用于读取管道,另一个用于写入管道。
父子进程通信:通常,匿名管道用于父子进程之间的通信。在创建子进程后,父进程可以将数据写入管道,而子进程则可以从管道中读取这些数据。
半双工:匿名管道是半双工的,意味着数据只能在一个方向上流动。如果需要双向通信,则需要创建两个管道,或者使用其他的进程间通信机制,比如命名管道或套接字。
进程同步:匿名管道通常用于进程间的同步和协作。一个进程可能会阻塞在读取管道上,直到另一个进程写入数据到管道中为止。
匿名管道在 Unix 系统中被广泛应用,特别是在 shell 编程和进程间通信方面。它提供了一种简单而有效的方式,允许不同进程之间进行数据交换和协作

我也有专门创建管道的函数pipe
在这里插入图片描述
我们可以来试一下:

#include<iostream>
#include<unistd.h>
#include<cassert>
using namespace std;int main()
{int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);cout<<"pipefd[0]"<<"--->"<<pipefd[0]<<"pipefd[1]"<<"--->"<<pipefd[1]<<endl;return 0;
}

运行:
在这里插入图片描述
这里我们发现pipefd[0]指代的是3,而我们的pipefd[1]指代的是4。其实也很好理解,因为0,1,2被标准输入,标准输出,标准错误占了。所以从3开始。

同时,如果我么查手册会看到这样一段话:
在这里插入图片描述
这段话的主要意思是pipefd[0]是读端,而pipefd[1]是写端。这为我们以后哪个开哪个关提供了依据。

观察匿名管道现象

我们先搭建架子来观察我们匿名管道的现象:

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");}if(id ==0){//子进程要做的事exit(0);}//父进程要做的事//回收子进程pid_t rid = waitpid(id,nullptr,0);if(rid == id){cout<<"wait success"<<endl;}return 0;
}

现在我们想让子进程写,父进程读,我们把相应用不到的管道关闭:

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");return 1;}if(id ==0){//子进程要做的事close(pipefd[0]); //关闭读的通道exit(0);}//父进程要做的事close(pipefd[1]); //关闭写的通道//回收子进程pid_t rid = waitpid(id,nullptr,0);if(rid == id){cout<<"wait success"<<endl;}return 0;
}

我们让子进程写入一些东西,然后让父进程来读,看看行不行:

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 1024int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");return 1;}if(id ==0){//子进程要做的事close(pipefd[0]); //关闭读的通道//向管道写入int cnt = 10;while(cnt){//缓冲区char message[MAX];//向缓冲区里写snprintf(message,sizeof(message),"hello father I am child my pid:%d cnt:%d ", getpid(),cnt);cnt--;//向管道写write(pipefd[1],message,strlen(message));sleep(1);}exit(0);}//父进程要做的事close(pipefd[1]); //关闭写的通道//从管道中读取数据char buffer[MAX];while(true){ssize_t n = read(pipefd[0],buffer,sizeof(buffer));if(n > 0){cout << getpid() << "," << "chid say :" << buffer << "to me" << endl;}}//回收子进程pid_t rid = waitpid(id,nullptr,0);if(rid == id){cout<<"wait success"<<endl;}return 0;
}

在这里插入图片描述
我们看到父进程真的拿到了子进程写的东西,这就是一个最基本的管道的应用。

读写端的几种情况

写端慢,读端快

我们模拟一下,写端慢,读端快的情况

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 1024int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");return 1;}if(id ==0){//子进程要做的事close(pipefd[0]); //关闭读的通道//向管道写入int cnt = 10;while(cnt){//缓冲区char message[MAX];//向缓冲区里写snprintf(message,sizeof(message),"hello father I am child my pid:%d cnt:%d ", getpid(),cnt);cnt--;//向管道写write(pipefd[1],message,strlen(message));sleep(100); //模拟写端慢}exit(0);}//父进程要做的事close(pipefd[1]); //关闭写的通道//从管道中读取数据char buffer[MAX];while(true){ssize_t n = read(pipefd[0],buffer,sizeof(buffer));if(n > 0){cout << getpid() << "," << "chid say :" << buffer << "to me" << endl;}}//回收子进程pid_t rid = waitpid(id,nullptr,0);if(rid == id){cout<<"wait success"<<endl;}return 0;
}

在这里插入图片描述
我们发现父进程处于一个休眠的状态,很明显,它是在等待我们的子进程进行写入。

这里我们可以得出匿名管道具有同步机制,读端和写端是协同工作的。

写端快,读端慢

我们调换一下,让写端快,读端快:

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 1024int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");return 1;}if(id ==0){//子进程要做的事close(pipefd[0]); //关闭读的通道//向管道写入int cnt = 10000;while(cnt){//缓冲区char message[MAX];//向缓冲区里写snprintf(message,sizeof(message),"hello father I am child my pid:%d cnt:%d ", getpid(),cnt);cnt--;//向管道写write(pipefd[1],message,strlen(message));cout<<"writing......"<<endl;}exit(0);}//父进程要做的事close(pipefd[1]); //关闭写的通道//从管道中读取数据char buffer[MAX];while(true){sleep(2); //睡眠2秒ssize_t n = read(pipefd[0],buffer,sizeof(buffer));if(n > 0){cout << getpid() << "," << "chid say :" << buffer << "to me" << endl;}}//回收子进程pid_t rid = waitpid(id,nullptr,0);if(rid == id){cout<<"wait success"<<endl;}return 0;
}

执行:
在这里插入图片描述
过了2秒之后:
在这里插入图片描述
数据一瞬间出来了。

这里我们可以得出匿名管道是面向字节流的,它没有硬性规定我写一条你必须马上读一条,而是以字节流的形式读或写。

管道的大小

我们可以写一段代码来测试我们管道的大小:

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 1024int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");return 1;}if(id ==0){//子进程要做的事close(pipefd[0]); //关闭读的通道//向管道写入int cnt = 0;while(1){//   //缓冲区//   char message[MAX];//   //向缓冲区里写//   snprintf(message,sizeof(message),"hello father I am child my pid:%d cnt:%d ", getpid(),cnt);//   cnt--;//   //向管道写//   write(pipefd[1],message,strlen(message));//   cout<<"writing......"<<endl;char c = 'a';write(pipefd[1], &c, 1);cnt++;cout << "write ....: " << cnt << endl;}exit(0);}//父进程要做的事close(pipefd[1]); //关闭写的通道//从管道中读取数据char buffer[MAX];while(true){// sleep(2); //睡眠2秒// ssize_t n = read(pipefd[0],buffer,sizeof(buffer));// if(n > 0)// {//    cout << getpid() << "," << "chid say :" << buffer << "to me" << endl;// }}//回收子进程pid_t rid = waitpid(id,nullptr,0);if(rid == id){cout<<"wait success"<<endl;}return 0;
}

在这里插入图片描述
我们发现最后结果是65536,折合下来也就是64kb左右的大小。

我们也可以用指令来查看管道大小:ulimit -a
在这里插入图片描述

我们查看的管道大小为512 * 8 = 4kb,好像比我们看到的小。这个其实不是真正的大小。

写端关闭,读端一直读

我们现在让写段写一段时间后直接关闭,但是读端没有关闭:

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 1024int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");return 1;}if(id ==0){//子进程要做的事close(pipefd[0]); //关闭读的通道//向管道写入int cnt = 0;while(1){//缓冲区char message[MAX];//向缓冲区里写snprintf(message,sizeof(message),"hello father I am child my pid:%d cnt:%d ", getpid(),cnt);cnt++;//向管道写write(pipefd[1],message,strlen(message));//跳出if(cnt > 3) break;// char c = 'a';// write(pipefd[1], &c, 1);// cnt++;// cout << "write ....: " << cnt << endl;}//关闭写端close(pipefd[1]);exit(0);}//父进程要做的事close(pipefd[1]); //关闭写的通道//从管道中读取数据char buffer[MAX];while(true){//sleep(2); //睡眠2秒ssize_t n = read(pipefd[0],buffer,sizeof(buffer));if(n > 0){cout << getpid() << "," << "chid say :" << buffer << "to me" << endl;}cout<<"father return value:"<< n << endl;sleep(1);}//回收子进程pid_t rid = waitpid(id,nullptr,0);if(rid == id){cout<<"wait success"<<endl;}return 0;
}

在这里插入图片描述
这样表示:写端关闭,读端一直读取, 读端会读到read返回值为0, 表示读到文件结尾

同时注意,进程退出,管道自动关闭

写端一直写,读端关闭

#include<iostream>
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string.h>
using namespace std;
#define MAX 1024int main()
{//建立管道int pipefd[2] = {0};int n = pipe(pipefd);assert(n == 0);//创建子进程pid_t id = fork();//子进程if(id < 0){perror("fork fail");return 1;}if(id ==0){//子进程要做的事close(pipefd[0]); //关闭读的通道//向管道写入int cnt = 0;while(true){//缓冲区char message[MAX];//向缓冲区里写snprintf(message,sizeof(message),"hello father I am child my pid:%d cnt:%d ", getpid(),cnt);cnt++;//向管道写write(pipefd[1],message,strlen(message));sleep(1);//跳出//if(cnt > 3) break;// char c = 'a';// write(pipefd[1], &c, 1);// cnt++;// cout << "write ....: " << cnt << endl;sleep(1);}//关闭写端//close(pipefd[1]);exit(0);}//父进程要做的事close(pipefd[1]); //关闭写的通道//从管道中读取数据char buffer[MAX];while(true){//sleep(2); //睡眠2秒ssize_t n = read(pipefd[0],buffer,sizeof(buffer));if(n > 0){cout << getpid() << "," << "chid say :" << buffer << "to me" << endl;}cout<<"father return value:"<< n << endl;sleep(1);//直接跳出break;}//关闭读端close(pipefd[0]);sleep(5);int status = 0;pid_t rid = waitpid(id, &status, 0);if (rid == id){cout << "wait success, child exit sig: " << (status&0x7F) << endl;}// //回收子进程// pid_t rid = waitpid(id,nullptr,0);// if(rid == id)// {//    cout<<"wait success"<<endl;// }return 0;
}

我们得到一下它的信号:
在这里插入图片描述
我们查一下13号信号:
在这里插入图片描述
13号信号是:SIGPIPE:

SIGPIPE 是在进程向一个已经被关闭的管道(或者其他的类似的通信方式)写入数据时,内核向该进程发送的信号。这个信号的默认行为是终止进程。
常见的场景是,一个进程向另一个进程通过管道发送数据,但接收数据的进程提前退出,导致写入数据的进程尝试往已关闭的管道写入数据。在这种情况下,内核会发送 SIGPIPE 信号给写入数据的进程,通知它目标进程已经退出,不再接收数据。

所以我们才有上述现象。

总结一下管道有4种情况:

管道的4种情况

  1. 正常情况,如果管道没有数据了,读端必须等待,直到有数据为止(写端写入数据了)
  2. 正常情况,如果管道被写满了,写端必须等待,直到有空间为止(读端读走数据)
  3. 写端关闭,读端一直读取, 读端会读到read返回值为0, 表示读到文件结尾
  4. 读端关闭,写端一直写入,OS会直接杀掉写端进程,通过想目标进程发送SIGPIPE(13)信号,终止目标进程

5种特性:

管道的5种特性

  1. 匿名管道,可以允许具有血缘关系的进程之间进行进程间通信,常用与父子,仅限于此
  2. 匿名管道,默认给读写端要提供同步机制 — 了解现象就行
  3. 面向字节流的 — 了解现象就行
  4. 管道的生命周期是随进程的
  5. 管道是单向通信的,半双工通信的一种特殊情况

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

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

相关文章

bert 相似度任务训练,简单版本

目录 任务 代码 train.py predit.py 数据 任务 使用 bert-base-chinese 训练相似度任务&#xff0c;参考&#xff1a;微调BERT模型实现相似性判断 - 知乎 参考他上面代码&#xff0c;他使用的是 BertForNextSentencePrediction 模型&#xff0c;BertForNextSentencePred…

thinkphp学习10-数据库的修改删除

数据修改 使用 update()方法来修改数据&#xff0c;修改成功返回影响行数&#xff0c;没有修改返回 0 public function index(){$data [username > 孙悟空1,];return Db::name(user)->where(id,11)->update($data);}如果修改数据包含了主键信息&#xff0c;比如 i…

STM32标准库开发——BKP备份RTC时钟

备份寄存器BKP(Backup Registers) 由于RTC与BKP关联性较高&#xff0c;所以RTC的时钟校准寄存器以及一些功能都放在了BKP中。TAMPER引脚主要用于防止芯片数据泄露&#xff0c;可以设计一个机关当TAMPER引脚发生电平跳变时自动清除寄存器内数据不同芯片BKP区别&#xff0c;主要体…

c++入门(2)

上期我们说到了部分c修补C语言的不足&#xff0c;今天我们将剩下的一一说清楚。 函数重载 (1).函数重载的形式 C语言不允许函数名相同的同时存在&#xff0c;但是C允许同名函数存在&#xff0c;但是有要求&#xff1a;函数名相同&#xff0c;参数不同&#xff0c;构成函数重…

【数据结构-图论】并查集

并查集&#xff08;Union-Find&#xff09;是一种数据结构&#xff0c;它提供了处理一些不交集的合并及查询问题的高效方法。并查集主要支持两种操作&#xff1a; 查找&#xff08;Find&#xff09;&#xff1a;确定某个元素属于哪个子集&#xff0c;这通常意味着找到该子集的…

人大金仓与mysql的差异与替换

人大金仓中不能使用~下面的符号&#xff0c;字段中使用”&#xff0c;无法识别建表语句 创建表时语句中只定义字段名.字段类型.是否是否为空 Varchar类型改为varchar&#xff08;长度 char&#xff09; Int(0) 类型为int4 定义主键&#xff1a;CONSTRAINT 键名 主键类型&#x…

Found option without preceding group in config file 问题解决

方法就是用记事本打开 然后 左上角点击 文件 有另存为 就可以选择编码格式

Linux设置程序任意位置执行(设置环境变量)

问题 直接编译出来的可执行程序在执行时需要写出完整路径比较麻烦&#xff0c;设置环境变量可以实现在任意位置直接运行。 解决 1.打开.bashrc文件 vim ~/.bashrc 2.修改该文件&#xff08;实现将/home/zhangziheng/file/seqrequester/build/bin&#xff0c;路径下的可执…

第六节:Vben Admin权限-后端控制方式

系列文章目录 第一节:Vben Admin介绍和初次运行 第二节:Vben Admin 登录逻辑梳理和对接后端准备 第三节:Vben Admin登录对接后端login接口 第四节:Vben Admin登录对接后端getUserInfo接口 第五节:Vben Admin权限-前端控制方式 文章目录 系列文章目录前言一、角色权限(后端…

【办公类-18-03】(Python)中班米罗可儿证书批量生成打印(班级、姓名)

作品展示——米罗可儿证书打印幼儿姓名 背景需求 2024年3月1日&#xff0c;中4班孩子一起整理美术操作材料《米罗可儿》的操作本——将每一页纸撕下来&#xff0c;分类摆放、确保纸张上下位置正确。每位孩子们都非常厉害&#xff0c;不仅完成了自己的一本&#xff0c;还将没有…

C++数据结构与算法——二叉搜索树的属性

C第二阶段——数据结构和算法&#xff0c;之前学过一点点数据结构&#xff0c;当时是基于Python来学习的&#xff0c;现在基于C查漏补缺&#xff0c;尤其是树的部分。这一部分计划一个月&#xff0c;主要利用代码随想录来学习&#xff0c;刷题使用力扣网站&#xff0c;不定时更…

Vue2:路由history模式的项目部署后页面刷新404问题处理

一、问题描述 我们把Vue项目的路由模式&#xff0c;设置成history 然后&#xff0c;build 并把dist中的代码部署到nodeexpress服务中 访问页面后&#xff0c;刷新页面报404问题 二、原因分析 server.js文件 会发现&#xff0c;文件中配置的路径没有Vue项目中对应的路径 所以…

Nacos进阶

目录 Nacos支持三种配置加载方案 Namespace方案 DataID方案 Group方案 同时加载多个配置集 Nacos支持三种配置加载方案 Nacos支持“Namespacegroupdata ID”的配置解决方案。 详情见&#xff1a;Nacos config alibaba/spring-cloud-alibaba Wiki GitHub Namespace方案…

《TCP/IP详解 卷一》第12章 TCP初步介绍

目录 12.1 引言 12.1.1 ARQ和重传 12.1.2 滑动窗口 12.1.3 变量窗口&#xff1a;流量控制和拥塞控制 12.1.4 设置重传的超时值 12.2 TCP的引入 12.2.1 TCP服务模型 12.2.2 TCP可靠性 12.3 TCP头部和封装 12.4 总结 12.1 引言 关于TCP详细内容&#xff0c;原书有5个章…

【C++ map和set】

文章目录 map和set序列式容器和关联式容器键值对setset的主要操作 mapmap主要操作 multiset和multimap map和set 序列式容器和关联式容器 之前我们接触的vector,list,deque等&#xff0c;这些容器统称为序列式容器&#xff0c;其底层为线性序列的的数据结构&#xff0c;里面存…

【LV14 day4 字符设备驱动基础框架】

一、字符设备驱动框架解析 设备的操作函数如果比喻是桩的话&#xff08;性质类似于设备操作函数的函数&#xff0c;在一些场合被称为桩函数&#xff09;&#xff0c;则&#xff1a; 驱动实现设备操作函数 ----------- 做桩 insmod调用的init函数主要作用 --------- 钉桩 rm…

都说了能不动就别动,非要去调整,出生产事故了吧

MyBatis 替换成 MyBatis-Plus 背景介绍 一个老项目&#xff0c;数据库用的是 MySQL 5.7.36 &#xff0c; ORM 框架用的 MyBatis 3.5.0 &#xff0c; mysql-connector-java 版本是 5.1.26 新来了一个干练的小伙&#xff0c;精力充沛&#xff0c;看着就是一个喜欢折腾的主 他…

leetcode 3.1

leetcode hot 100 双指针1.三数之和2.接雨水 多维动态规划1.最长公共子序列 双指针 1.三数之和 三数之和 排序 双指针的方法&#xff0c;固定一个数nums[i], 用两数和找target - nums[i] 的数需要注意两点: 1.需要去掉重复数字 while (l < r && nums[l] nums[…

社交APP开发能给用户带来什么

现在的社交软件也非常的多&#xff0c;每款社交软件都有自己的特色&#xff0c;社交软件是日常中必备的软件&#xff0c;不管是生活交流还是感情工作交流都是比较方便的&#xff0c;因为社交软件满足了日常的远程交流问题&#xff0c;所以开发社交软件也会逐渐的流行起来的。 …

【Qt学习】QLCDNumber的介绍与实例使用(倒计时功能)

文章目录 1. 介绍2. 实例 - QLCDNumber倒计时3. 资源文件 1. 介绍 QLCDNumber是Qt框架中用于显示数字的控件&#xff0c;它模拟了一个液晶数字显示屏。 在Designer界面中显示如下&#xff1a; 有以下 常用属性&#xff1a; 属性描述intValue获取或设置QLCDNumber显示的整数…