【Linux】进程状态

文章目录

  • 📖 前言
  • 1. 父进程与子进程
  • 2. fork函数创建子进程
    • 2.1 认识fork函数:
    • 2.2 fork函数两个返回值的原因:
    • 2.3 fork函数的返回值意义:
  • 3. 进程状态
    • 3.1 运行状态(R):
    • 3.2 终止状态(X):
    • 3.2 阻塞状态(S):
    • 3.3 进程挂起:
    • 3.4 深度睡眠状态:(D)
    • 3.5 僵尸状态(Z):
      • 3.5 - 1 模拟僵尸进程
      • 3.5 - 2 长时间僵尸的危害
    • 3.6 孤儿进程:
    • 3.7 暂停状态:(T / t)
      • 3.7 - 1 T(stopped)
      • 3.7 - 1 t(tracing stop)

📖 前言

在我们有了进程的初步基本概念之后,我们就要来学习一下如何创建进程,进程的几种状态,进程的优先级的问题,搬好小板凳要开讲了🙋🙋🙋……

本文实验系统:CentOS 7.6~


1. 父进程与子进程

父进程:指已创建一个或多个子进程的进程~

我们通过getpid函数来获取当前进程的ID,也可以通过getppid来获取父进程的ID:

在这里插入图片描述
代码演示:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    while(1)
    {
        printf("I am a process! pid: %d ppid: %d\n",getpid(), getppid());
        sleep(1);
    }

    return 0;
}

我们多次执行上述代码观察当前进程和其父进程的ID:

在这里插入图片描述
之前的只是我们知道了,当每次执行一个可执行程序之后,进程的ID都会改变,上图也验证了这一点,但是我们惊奇的发现,为啥父进程的ID始终都是一个值,一直都是不变的呢??

在这里插入图片描述
几乎我们在命令行上所执行的所有的指令(你的cmd),都是bash进程的子进程!

衍生问题:

  • bash怎么创建的子进程?
  • bash怎么让子进程执行我的程序?
  • bash的父进程又是谁?

我们后面再说…


2. fork函数创建子进程

2.1 认识fork函数:

fork函数是用来创建子进程的,它有两个返回值。

fork函数:
在这里插入图片描述
fork函数的返回值:

在这里插入图片描述

  • 成功的话:将子进程的pid返回给父进程,0被返回给子进程。
  • 失败的话:-1直接返回给父进程,没有子进程没创建。

这就有点违背我们之前学习的认知了,因为我们之前接触的函数有返回值的也就只有一个返回值,从来没听过有两个返回值的说法。

代码演示:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t id  = fork();

    printf("Hello World!  id = %d\n", id);

    return 0;
}

在这里插入图片描述
运行的结果非常的诡异:一条打印语句竟然有两个打印结果,并且,我们并没有对id值做任何修改,但是结果却是有两个不一样的id值。

这在我们之前的编程语言学习中是不可能的,我们是不接受的。

我们再来看一段代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t id = fork();
    //id == 0 : 子进程 , id > 0 : 父进程
    
    if(id == 0)
    {
        while(1)
        {
            printf("我是子进程,我的pid:%d,我的父进程是:%d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else  
    {
        while(1)
        {
            printf("我是父进程,我的pid:%d,我的父进程是:%d\n", getpid(), getppid());
            sleep(1);
        }
    }

    return 0;
}

在这里插入图片描述

  • C语言上ifelse if可以同时执行吗?不能!!
  • C语言中,有没有可能两个以上的死循环同时运行?不能!!

但是上述代码执行结果却是和我们C语言中相违背了~


2.2 fork函数两个返回值的原因:

如何解释呢?fork如何做到会有不同的返回值?

既然是有两个返回值,那么一定是曾经被返回了两次,要不然怎么可能有两个返回值呢?

要想弄清楚这个问题,我们就要知道一个C语言阶段的知识:

调用一个函数,当这个函数准备return的时候,这个函数的核心功能完成了吗??
答案是肯定的!!

  • fork之后,OS做了什么?是不是系统多了一个进程。
  • 那么我们知道进程是:task_struct + 数据和代码
  • 那么子进程也是:task_struct + 子进程的数据和代码
  • 子进程的task_ stuct对象内部的数据从哪里来呢??基本是从父进程继承下来的。
  • 子进程执行代码,计算数据的,子进程的代码从哪里来呢??没有地方来!!
  • 所以子进程和父进程执行同样的代码,fork之后,父子进程代码共享!!

这也就实现了,通过不同的返回值,让不同的进程执行不同的代码。

父进程return一次,子进程return一次,不就是两次返回吗,不就有两个返回值吗?

  • fork之后,父进程和子进程会共享代码,一般都会执行后续的代码 — printf为什么会打印两次的问题。
  • fork之后,父进程和子进程返回值不同,可以通过不同的返回值,判断让父子执行不同的代码块!!

2.3 fork函数的返回值意义:

fork()为什么给父进程返回子进程的pid,给子进程返回0?

在之前学习过的二叉树中,我们知道一个父结点可以有多个孩子结点,但是一个孩子结点只能有唯一的父亲节点。

  • 进程也是这样,一个父进程可以有一个或多个子进程,但是一个子进程只能有唯一的父进程。
  • 父进程必须有标识子进程的方案,fork之后,给父进程返回子进程的pid!
  • 子进程最重要的是要知道自己被创建成功了,因为子进程找父进程成本非常低!getppid()
  • 一个子进程只有一个父进程,给子进程返回0,给父进程返回自己的pid。
    • 一个是让自子进程得知自己被创建成功了。
    • 一个是让父进程更好的去控制子进程。
    • 子进程有方法获取父进程pid,就没必要返回了。

补充:

  • 进程是由task_struct 和 对应的数据和代码组成
  • 那么我们平时用的指令的执行后,它的进程对应的代码在哪呢?
  • 我们以ls为例:
    • ls变成进程之后,该进程的代码就是从磁盘/usr/bin/ls路径下读取数据代码。

3. 进程状态

操作系统就像是计算机里的哲学一样,因为操作系统这门学科讲的范围很宽泛,它的理论内容适用于各个操作系统,而我们要具体的学习某一款操作系统那就是Linux

首先我们凡是说进程,就必须先想到进程的task_ struct

  • 进程状态本质上是个整数,整数在进程的task struct中。
  • task_ struct中会包含进程的相关的信息。

我们来看一下进程的几种状态:

在这里插入图片描述
我们先来看一下进程状态之间的关系:
在这里插入图片描述
上面一大堆乱七八糟的,看上去是真的乱,真让人头大,我们慢慢来讲~🙋🙋🙋……

3.1 运行状态(R):

  • 运行状态:是进程在CPU上运行,就叫运行态吗??答案是否定的!!
  • 也叫R状态,running~

概念:

一个进程被运行,操作系统当中每个CPU,系统都会个CPU创建一个runqueue,所以一个进程想被调动,说白了就是将自己的进程放到运行队列当中就可以。

如何理解进程被运行:

进程只要在运行队列中叫做运行态,不代表正在运行,代表我已经准备好了,随时可以调度!!

在这里插入图片描述
进程排队实际上是让这个进程控制块去排队。

3.2 终止状态(X):

  • 终止状态:这个进程已经被释放,就叫做终止态吗??答案是否定的!!
  • 也叫X状态,dead~

是该进程还在,只不过永远不运行了,随时等待被释放!!

  • 进程都终止了,为什么不立马释放对应的资源,而要维护一个终止态??
  • 释放要花时间吗??有没有可能,当前你的操作系统很忙呢??

进程终止状态:进程已完成执行。

终止就是最终资源释放,但是PCB控制块至少还在,要让操作系统来释放。

3.2 阻塞状态(S):

  1. 一个进程,使用资源的时候,可不仅仅是在申请CPU资源!
  2. 进程可能申请更多的其他资源:磁盘,网卡,显卡,显示器资源,声卡 / 音响。
  • 如果我们申请CPU资源,暂时无法得到满足,需要排队的 — 运行队列
  • 那么如果我们申请其他慢设备的资源呢 — 也是需要排队的!(task_ struct在进程队列排队)
  • 阻塞状态,也叫S状态,sleeping~

重点:

当进程访问某些资源(磁盘网卡),该资源如果暂时没有准备好,或者正在给其他进程提供服务,此时:

  1. 当前进程要从runqueue中移除。
  2. 将当前进程放入对应设备的描述结构体中的等待队列!

网卡,声卡,显卡每一个操作系统都要先管理起来,所以操作系统要先描述再组织~

在这里插入图片描述

  • 当我们的进程此时在等待外部资源的时候,该进程的代码,不会被执!!
  • 我的进程卡住了 — 进程阻塞!上层看来就是某些任务卡住了。

当设备在硬件层面准备好了,一定会通过某种方式让操作系统知道,再将该进程的PCB放在CPU的运行队列当中。

补充:

  • CPU运行的速度非常快,但是运行队列的周转周期非常短,看起来所有进程都在运行。
  • 单核CPU在任意时间点都只能运行一个进程。

我们来看一下S状态:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    while(1)
    {
        printf("I am a process: %d\n", getpid());
    }

    return 0;
}

在这里插入图片描述
有个疑问,为什么我们一直向显示器打印,但却是S状态呢?

  • 我们不能用我们的认知速度来认知计算机
  • 因为CPU足够快,外设又很慢,CPU速度的速度是远大于外设的
  • 大部分时间进程是在等待外设的显示器准备好的
  • 所以大部分时间都是S状态,都是睡眠阻塞状态
  • 只有很小的机会查看进程才能看到R运行状态

总结:

虽然一直在刷屏,但是还是S状态,原因也是在printf上,不断地往显示器上打印,但是显示器是个外设速度非常慢,即便是闲着准备好被刷新也需要花费时间。这个进程90%的情况都是在等,在等显示器就绪。
只有光是一个死循环,不调用外设的时候才是一直处于R状态。

3.3 进程挂起:

  • 如果内存不足了怎么办??操作系统就要帮我们进行 “辗转腾挪” ~~
  • 短期内不会被调度(你等的资源,短期内不会就绪)进程,它的代码和数据依旧在内存中!!就是白白的浪费空间!
  • OS就会把该进程的代码和数据置换到磁盘上!

概念:

一个进程对应的代码和数据,被操作系统因为内存资源不足而导致操作系统将该进程的代码和是数据临时的置换到磁盘当中,此时叫做进程挂起。

在这里插入图片描述
只把描述进程的PCB留在了内存中。

往往内存不足的时候,伴随着磁盘被高频率访问!

3.4 深度睡眠状态:(D)

首先D状态也是一种阻塞状态,而我们上述的S状态也是阻塞状态,只是D状态是一种深度睡眠~

  • D状态可以理解为deep - 深 / disk - 磁盘的意思

假设场景:

当一个进程向磁盘写文件的时候,由于要写的文件很大,所以进程要在那里等,如果等的时间太长了的话,操作系统见到一个进程在那里很悠闲直接把它干掉了,那等磁盘将文件写完之后,回头一看,傻眼了,进程不见了,那写入的文件怎么处理呢??如果该文件写入失败了,结果返回的时候发现进程不见了,那么数据就丢了,后果很严重。
尽然进程要等,就是要等一个返回值,就是为了判断文件写成功了没!!

所以这个进程不能随便杀掉,所以操作系统就将该进程设置成了D状态!!

  • 凡是D状态的进程,操作系统无权杀掉该进程,只能等该进程自己醒来。
  • D状态的进程操作系统没权利将其杀掉,只能通过关机重启 or 拔掉电源的方式来强制杀掉该进程。
  • 如果一个系统当中存在大量的D状态进程,关机都关不掉。
  • 一般而言,linux中,如果我们等待的是磁盘资源,我们进程阻塞所处的状态就是D。

不过这种情况不多见,很难能见到~

补充:

  • 有时候闪退的问题,是服务器压力过大,OS是会终止用户进程的!

3.5 僵尸状态(Z):

僵尸进程:Z - zombie

  • X状态:我们上面说的死亡,状态可以随时将他的资源回收掉。
  • Z状态:僵尸状态先不急进入X (死亡状态)

当一个Linux中的进程退出的时候,一般不会直接进入X状态(死亡,资源可以立与回收),而是进入Z状态。

我们不禁发出疑问,为什么??

  • 首先我们要知道,进程为什么被创建出来呢??
    • 一定是因为要有任务让这个进程执行。
  • 当该进程退出的时候,我们怎么知道,这个进程把任务给我们完成的如何了呢??
    • 一般需要将进程的执行结果告知给父进程OS。

既然如此,那么父进程派生的子进程,任务执行完了吗??执行的对不对??中途有无被操作系统杀掉??这些情况都需要告知父进程或者操作系统。

  • 进程Z,就是为了维护退出信息,可以让父进程或者OS读取的!
  • 操作系统 or 父进程知道之后可以做第二次决策。
  • 僵尸进程存在的意义就是说明这个进程退出的时候是因为什么原因退出的。

衍生问题:

  • 进程退出的情况有哪些?怎么退出进程?
  • 操作系统可以读取子进程的退出信息,因为PCB就是它创建的。
  • 父进程如何读取子进程的退出信息?
  • 父进程如何让子进程的状态由Z变成X?

以后再说…

3.5 - 1 模拟僵尸进程

如果创建子进程,子进程退出了,父进程不退出,也不等待子进程,子进程退出之后所处的状态就是Z状态。(ps:所谓等待子进程就是回收)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 

int main()
{
    pid_t id = fork();
    
    if(id == 0)
    {
        //child
        int cnt = 5;
        while(cnt)
        {
            printf("我是子进程,我剩下 %d S\n", cnt);
            cnt--;
            sleep(1);
        }
        printf("我是子进程,我已经僵尸了,等待被检测\n");
        exit(0);
    }
    else 
    {
        while(1)
        {
            sleep(1);
        }
    }

    return 0;
}

子进程五秒后退出,父进程一直在跑,也不回收子进程。我们代码没有写回收,所以子进程就是没有回收。

写一个可以在屏幕上循环打印出进程状态的脚本:

在这里插入图片描述
前五秒的进程状态如下:

在这里插入图片描述
五秒之后的进程状态:

在这里插入图片描述

3.5 - 2 长时间僵尸的危害

  • 如果没有人回收子进程的僵尸,该状态会一直维护!该进程的相关资源(task_struct) 不会被释放!一个很严重的问题那就是 — 内存泄漏!!

什么情况会一直僵尸?

  • 父进程不回收它,会一直僵尸状态。
  • 一个进程僵尸了,是不可被杀死的。都已经成僵尸了还怎么杀死~😂😂😂

一般必须要求父进程进行回收,后面说~

3.6 孤儿进程:

  • 子进程不退出,父进程先退出了。
  • 父进程的父进程是bash,会自动回收掉他的子进程,所以我们看不到该父进程的僵尸状态。

只需要将之前的代码稍微改一点:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 

int main()
{
    pid_t id = fork();
    
    if(id == 0)
    {
        //child
        while(1)
        {
            printf("我是子进程\n");
            sleep(1);
        }
        printf("我是子进程,我已经僵尸了,等待被检测\n");
    }
    else 
    {
        int cnt = 3;
        while(cnt) 
        {
            printf("我是父进程,我:%d\n", cnt--);
            sleep(1);
        }
        exit(0);
    }

    return 0;
}

子进程一直不退,父进程3秒后退出。

再用之前的方式来观察。

在这里插入图片描述
我们突然发现,父进程3秒后消失不见了,然后原来的S+变成了S

  • 状态后面有+的,代表这个进程是个前台进程能在键盘ctr/ + C的是前台进程后台进程ctr/ + C干不掉。
  • 孤儿进程没有那个+,它是个后台进程。

只能通过命令来杀,这个后台进程被杀掉之后操作系统就将其回收了。

kill -9 进程的pid

我们还发现子进程的pid变成了1:

  • 如果父进程提前退出,子进程还在运行,子进程会被1号进程领养!!
  • 如果父进程先退出了,此时子进程再想退出的时候就没人回收没人管了。
  • 所以此时给出的方案是,当一个子进程的父进程退出了,该子进程会被1号进程领养。(所以叫孤儿进程)
  • 1号进程就是操作系统

3.7 暂停状态:(T / t)

  • 暂停状态有两个:一个是T,一个是t

3.7 - 1 T(stopped)

我们先来将暂停状态T

我们先来写一段死循环打印:

#include <stdio.h>
#include <unistd.h> 

int main()
{
    while(1)
    {
        printf("Hello World!\n");
        sleep(1);
    }

    return 0;
}

它肯定是S状态。

我们上述用kill -9 进程ID的方式来杀掉进程,还有kill其他的选项:

在这里插入图片描述
我们通kill -19 进程ID就将这个进程暂停掉了:
在这里插入图片描述
我们可以用kill -18 进程ID再将进程恢复启动起来。

补充:

在这里插入图片描述

3.7 - 1 t(tracing stop)

  • tracing - 追踪~
  • 进程被调试的时候,遇到断点所处的状态。

在这里插入图片描述
此时我们再来查看一下进程:
在这里插入图片描述


我们再次回头看那张进程状态关系图,此时理解就不难了,随他怎么变,咱都能认得!!

  • 就绪: 就是外设准备好了,可以把对应的进程放到某个运行队列里了。等待某种资源的时候一旦就绪就能运行。
  • 挂起阻塞: 在阻塞的时候操作系统可以将进程换入换出,这就叫做挂起阻塞,意思就是一个进程是阻塞状态,就将其挂起来,此时进程没有被执行,代码也没有在内存当中,进程只是在等,PCB在内存中。
  • 挂起就绪: 阻塞状态操作系统嫌弃它太闲了,就讲它换出去了,外设就绪了,例如磁盘准备了,但是此时代码还在外头,这就叫做挂起就绪,此时再将代码再换入,现在这个进程整体准备好了,再放入运行队列。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FPGA基于SFP光口实现10G万兆网UDP通信 10G Ethernet Subsystem替代网络PHY芯片 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案4、vivado工程详解5、上板调试验证并演示6、福利&#xff1a;工程代码的获取 1、前言 目前网上的fpga实现udp基本生态如下&#xff1a; 1&#xff1a;verilog编写的udp收发器&#xff0c;但不带ping功能&#xff0c;这样的代…

Spring AOP核心概念与操作示例

AOP 核心概念 还记得我们Spring有两个核心的概念嘛&#xff1f;一个是IOC/DI&#xff0c;另一个是AOP咯。 先来认识两个概念&#xff1a; AOP(Aspect Oriented Programming)面向切面编程&#xff1b;作用&#xff1a;在不惊动原始设计的基础上为其进行功能增强&#xff0c;类…

《springboot实战》第六章 实现自定义全局异常处理

前言 springboot实现自定义全局异常处理&#xff0c;以及统一返回数据。 1、分析 首先&#xff0c;实现全局异常的流程 从图中可以看到&#xff0c;实现全局异常会需要这样几个类&#xff1a; 自定义异常接口类自定义异常枚举类自定义异常类自定义异常处理类自定义全局响应…

ROS学习第十二节——话题通信控制小乌龟

1.基操一下 首先打开小乌龟程序和键盘控制程序 rosrun turtlesim turtlesim_node rosrun turtlesim turtle_teleop_key 查看话题列表 rostopic list 打开计算图查看具体是那个话题在起作用 rqt_graph 从上图可以看到两个节点之间的话题是 /turtle1/cmd_vel 使用以下命令获…

linux及openEuler破解root密码

第一步&#xff1a;开机的时候按键盘的字母 E 键&#xff0c; 进入引导模式 第二步&#xff1a;进入引导模式 &#xff1a;找到linux这一行&#xff0c;按键盘上的end 键&#xff0c;跳转到行尾&#xff0c;输入&#xff1a; init/bin/sh 修改完后&#xff0c;按键盘上的 ctr…

哪种无线耳机音质最好?盘点2023四款好音质蓝牙耳机

随着蓝牙技术的发展&#xff0c;近几年人们对于蓝牙耳机的需求也在不断增加。但&#xff0c;蓝牙耳机自始至终都是用来听的&#xff0c;所以音质对于一款蓝牙耳机来说还是很重要的。下面&#xff0c;我来给大家推荐四款好音质蓝牙耳机&#xff0c;可以当个参考。 一、南卡小音舱…

JavaEE-轻松了解网络原理之TCP协议

目录 TCP协议TCP协议数据格式TCP原理确认应答超时重传连接管理三次握手四次挥手 滑动窗口流量控制拥塞控制延迟应答捎带应答面向字节流异常问题 TCP协议 TCP&#xff0c;即Transmission Control Protocol&#xff0c;传输控制协议. TCP协议数据格式 16位源端口号与16位目的端…

Doris(8):数据导入(Load)之Insert Into

Insert Into 语句的使用方式和 MySQL 等数据库中 Insert Into 语句的使用方式类似。但在 Doris 中&#xff0c;所有的数据写入都是一个独立的导入作业。所以这里将 Insert Into 也作为一种导入方式介绍。 主要的 Insert Into 命令包含以下两种&#xff1b; INSERT INTO tbl S…

微服务 - Redis缓存 · 数据结构 · 持久化 · 分布式 · 高并发

一、分布式解决 Session 的问题 在单站点中&#xff0c;可以将在线用户信息存储在Session中&#xff0c;随时变更获取信息&#xff1b;在多站点分布式集群如何做到Session共享呢&#xff1f;架设一个Session服务&#xff0c;供多服务使用。 频繁使用的数据存在DB端&#xff0…

如何使用镭速保护云存储数据安全

近年来&#xff0c;随着云计算的发展&#xff0c;远程系统上的数据存储变的越来越重要。云存储是一个以数据存储和管理为核心的云计算系统&#xff0c;给我们提供了一种全新的数据信息存储模式。但是&#xff0c;可以从全球任何地方访问和检索相同的数据。所需要的只是一个简单…

protobuf序列化原理、安装与应用

目录 protobuf序列化 protobuf的原理 protobuf 的安装 编译message文件 应用protobuf protobuf序列化 protobuf是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式&#xff0c;性能比json和xml真的强很多&#xff0c;毕竟google出品。 官网&#xff1a;https:…

第八章 法律关系

目录 第一节 法律关系的概念 一、法律关系的定义与特征 二、法律关系的种类 &#xff08;一&#xff09;纵向&#xff08;隶属&#xff09;的法律关系和横向&#xff08;平权&#xff09;的法律关系 &#xff08;二&#xff09;单向&#xff08;单务&#xff09;法律关系、双…

Dear ImGui结合CMake实现基于GLFW和OpenGL3的入门级hello world代码

Dear ImGui结合CMake实现基于GLFW和OpenGL3的入门级hello world代码 如需转载请标明出处&#xff1a;https://blog.csdn.net/itas109 技术交流&#xff1a;129518033 环境&#xff1a; OS: windows 10 / Ubuntu 22.04 imgui: 1.89.5 glw: 3.3.8前言 Dear ImGui 是一个 用于…

outlook邮箱pc/mac客户端下载 含最新版

新的 Outlook for Windows or mac 为 Outlook 应用带来了最新功能、智能辅助功能和新的新式简化设计。 你可以根据自己的风格定制它&#xff0c;并使用新的 Outlook for Windows/mac 执行更多操作&#xff01; 览版&#xff0c;与我们一起开始旅程&#xff0c;并帮助我们塑造新…

leetcode142. 环形链表 II

给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数…

python 打包新方案

首先是打包一个最简单的python 代码使用 pyinstaller import os #直接读取文件获得python.exe 路径 # 待执行python路径 with open("path_run.txt","r",encoding"utf-8") as f:python_exe,pyf.readlines() os.system("{} {}".format(p…

什么牌子的蓝牙耳机音质最好?盘点2023音质最好的蓝牙耳机

近几年&#xff0c;蓝牙耳机在日常生活中的出现频率越来越高&#xff0c;不管是运动、听歌、追剧、玩游戏等等都能看到蓝牙耳机的身影。接下来&#xff0c;我来给大家盘点几款音质好的蓝牙耳机&#xff0c;感兴趣的朋友可以了解一下。 一、南卡小音舱Lite2蓝牙耳机 参考价&…

服务器版本的表白墙

目录 1.步骤 2.提供两个接口: 3.流程 4.代码 1.前端代码 2.sql创建表 3.后端代码 MessageServlet.java DBUtil.java 1.步骤 1.约定前后端交互的接口 2.开发服务器代码 a.编写servlet处理前端发来的请求 b.编写数据库代码,存储获取关键的数据 3.开发客户端代码 a.基于…

zabbix搭建

1.环境 本实验使用一台centos7主机&#xff0c;关闭了firewalld和selinux服务&#xff0c;zabbix版本为5.0版本&#xff0c;mysql使用版本为5.7版本 若要搭建6.0以上版本的zabbix&#xff0c;则需要使用mysql 8.0以上的版本 其它版本的zabbix可参考zabbix官网:Download and…

shell编程入门 第一章 基本语法

shell编程的语法主要分为五个环节&#xff0c;分别是变量&#xff0c;字符串&#xff0c;运算符&#xff0c;流程控制&#xff0c;函数五大部分 shell编程的基础语法 一 变量1.1 shell变量名1.2 使用shell变量1.3只读变量1.4 删除变量 二 字符串2.1 定义时最好用双引号2.2获取字…