Linux 系统综述

Linux 系统综述

安装与管理

在 Linux 上面,没有双击安装这一说,因此想要安装,我们还得需要命令。CentOS 下面使用 rpm -i jdk-XXX_linux-x64_bin.rpm 进行安装,Ubuntu 下面使用 dpkg -i jdk-XXX_linux-x64_bin.deb 。其中 -i 就是 install 的意思。

主要记 CentOs 的指令。

在 Linux 下面,凭借 rpm -qadpkg -l 就可以查看安装的软件列表,-q 就是 query,a 就是 all,-l 的意思就是 list。

跟上 grep 更好用,如果单纯要查看,最好用 moreless 跟一下。前者只能向后翻页,后者更加强大。

如果要删除,可以用 rpm -edpkg -r-e 就是 erase,-r 就是 remove。

上面这些都是有『安装包』的情况下的操作,如何在没有安装包的情况下安装呢?CentOS 下面是 yum ,Ubuntu 下面是 apt-get 。例如搜索 jdk 、yum search jdkapt-cache search jdk ,可以搜索出很多很多可以安装的 jdk 版本。

选中一个之后,我们就可以进行安装了。你可以用 yum install java-11-openjdk.x86_64apt-get install openjdk-9-jdk 来进行安装。

安装以后,如何卸载呢?我们可以使用 yum erase java-11-openjdk.x86_64apt-get purge openjdk-9-jdk

对于 CentOs 来说,配置文件在 /etc/yum.repos.d/CentOS-Base.repo 里,在这里可以进行 yum 换源等操作。

其实无论是先下载再安装,还是通过软件管家进行安装,都是下载一些文件,然后将这些文件放在某个路径下,然后在相应的配置文件中配置一下。

运行与关闭

配置环境变量和 MacOs 一样,就不记录了。

后台运行使用 nohup 命令,就是 no hang up(不挂起)的意思,最后加一个 & ,就表示后台运行。最终命令的一般形式为 nohup command >out.file 2>&1 & 。这里面,“1”表示文件描述符 1,表示标准输出,“2”表示文件描述符 2,意思是标准错误输出,“2>&1”表示标准输出和错误输出合并了。合并到哪里去呢?到 out.file 里。

关闭指定进程:ps -ef |grep 关键字 |awk '{print $2}'|xargs kill -9

ps -ef 可以单独执行,列出所有正在运行的程序;

awk '{print $2}' 是指第二列的内容,是运行的程序 ID ;

可以通过 xargs 传递给 kill -9,也就是发给这个运行的程序一个信号,让它关闭。

Linux 也有相应的服务,这就是程序运行的第三种方式,以服务的方式运行。比如 MySQL ,安装完成以后通过命令 systemctl start mysql 启动 MySQL,通过 systemctl enable mysql 设置开机启动。之所以成为服务并且能够开机启动,是因为在 /lib/systemd/system 目录下会创建一个 XXX.service 的配置文件,里面定义了如何启动、如何关闭。

分支进程

在 Linux 里,要创建一个新的进程,需要一个老的进程调用 fork 来实现,其中老的进程叫作父进程(Parent Process),新的进程叫作子进程(Child Process)。对于 fork 系统调用的返回值,如果当前进程是子进程,就返回 0;如果当前进程是父进程,就返回子进程的进程号。对于子进程进行 execve 执行另外的操作,就形成了分支。

有个系统调用 waitpid ,父进程可以调用它,将子进程的进程号作为参数传给它,这样父进程就知道子进程运行完了没有,成功与否。

内存分配

系统分配内存时,当分配的内存数量比较小的时候,使用 brk,会和原来的堆的数据连在一起,这就像多分配两三个工位,在原来的区域旁边搬两把椅子就行了;当分配的内存数量比较大的时候,使用 mmap,会重新划分一块区域,也就是说,当办公空间需要太多的时候,索性来个一整块。

Linux 里有一个特点,那就是一切皆文件。每个文件,Linux 都会分配一个文件描述符(File Descriptor),这是一个整数。有了这个文件描述符,我们就可以使用系统调用,查看或者干预进程运行的方方面面。

信号与异常

对于一些不严重的信号,可以忽略,该干啥干啥,但是像 SIGKILL(用于终止一个进程的信号)和 SIGSTOP(用于中止一个进程的信号)是不能忽略的,可以执行对于该信号的默认动作。每种信号都定义了默认的动作,例如硬件故障,默认终止;也可以提供信号处理函数,可以通过 sigaction 系统调用,注册一个信号处理函数。

进程间通信

首先就是发个消息,不需要一段很长的数据,这种方式称为消息队列(Message Queue)。由于一个公司内的多个项目组沟通时,这个消息队列是在内核里的,我们可以通过 msgget 创建一个新的队列,msgsnd 将消息发送到消息队列,而消息接收方可以使用 msgrcv 从队列中取消息。

当消息内容较大,可以用内存共享,这时候,我们可以通过 shmget 创建一个共享内存块,通过 shmat 将共享内存映射到自己的内存空间,然后就可以读写了。共用内存可能存在竞争,这就是信号量的机制 Semaphore。

对于只允许一个人访问的需求,我们可以将信号量设为 1。当一个人要访问的时候,先调用 sem_wait 。如果这时候没有人访问,则占用这个信号量,他就可以开始访问了。

如果这个时候另一个人要访问,也会调用 sem_wait 。由于前一个人已经在访问了,所以后面这个人就必须等待上一个人访问完之后才能访问。当上一个人访问完毕后,会调用 sem_post 将信号量释放,于是下一个人等待结束,可以访问这个资源了。

Glib 与中介

Glibc 是 Linux 下使用的开源的标准 C 库,它是 GNU 发布的 libc 库。Glibc 为程序员提供丰富的 API,除了例如字符串处理、数学运算等用户态服务之外,最重要的是封装了操作系统提供的系统服务,即系统调用的封装。

每个特定的系统调用对应了至少一个 Glibc 封装的库函数,比如说,系统提供的打开文件系统调用 sys_open 对应的是 Glibc 中的 open 函数。

有时候,Glibc 一个单独的 API 可能调用多个系统调用,比如说,Glibc 提供的 printf 函数就会调用如 sys_opensys_mmapsys_writesys_close 等等系统调用。

也有时候,多个 API 也可能只对应同一个系统调用,如 Glibc 下实现的 malloccallocfree 等函数用来分配和释放内存,都利用了内核的 sys_brk 的系统调用。

总结