01 Linux操作系统

本文介绍了Linux操作系统中的基本概念和操作,包括用户和密码管理、程序的交互式与后台运行、服务启动与管理,以及系统调用如fork、waitpid。文章还涉及内存管理,如堆和栈,以及文件操作和进程间通信机制,如消息队列、共享内存和信号量。此外,讨论了网络通信的套接字和Glibc库的作用。
摘要由CSDN通过智能技术生成

快速上手的Linux指令

用户和密码

密码修改

passwd

用户添加

useradd yourusername

执行这个命令,一个用户就被创建了。它不会弹出什么让你输入密码之类的页面,就会直接返回了。因为接下来你需要自己调用 passwd cliu8 来设置密码,再进行登录。

程序运行的方式

一、 shell 在交互命令行里面运行

这样执行的程序可能需要和用户进行交互,例如允许让用户输入,然后输出结果也打印到交互命令行上。这种方式比较适合运行一些简单的命令,例如通过 date 获取当前时间。这种模式的缺点是,一旦当前的交互命令行退出,程序就停止运行了。

这样显然不能用来运行那些需要“永远“在线的程序。比如说,运行一个博客程序,我总不能老是开着交互命令行,博客才可以提供服务。一旦我要去睡觉了,关了命令行,我的博客别人就不能访问了,这样肯定是不行的。

二、后台运行

这个时候,我们往往使用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

从这个命令中,我们多少能看出 shell 的灵活性和精巧组合。

其中 ps -ef 可以单独执行,列出所有正在运行的程序,grep 上面我们介绍过了,通过关键字找到咱们刚才启动的程序。

awk 工具可以很灵活地对文本进行处理,这里的 awk '{print $2}'是指第二列的内容,是运行的程序 ID。我们可以通过 xargs 传递给 kill -9,也就是发给这个运行的程序一个信号,让它关闭。如果你已经知道运行的程序 ID,可以直接使用 kill 关闭运行的程序。

三、以服务的方式运行

在 Ubuntu 中,我们可以通过 apt-get install mysql-server 的方式安装 MySQL,然后通过命令systemctl start mysql启动 MySQL,通过systemctl enable mysql设置开机启动。之所以成为服务并且能够开机启动,是因为在 /lib/systemd/system 目录下会创建一个 XXX.service 的配置文件,里面定义了如何启动、如何关闭。

在 CentOS 里有些特殊,MySQL 被 Oracle 收购后,因为担心授权问题,改为使用 MariaDB,它是 MySQL 的一个分支。通过命令yum install mariadb-server mariadb进行安装,命令systemctl start mariadb启动,命令systemctl enable mariadb设置开机启动。同理,会在 /usr/lib/systemd/system 目录下,创建一个 XXX.service 的配置文件,从而成为一个服务。

关机和重启

关机

shutdown -h now

重启

reboot

系统调用

立项服务与进程管理

立项服务。对应到 Linux 操作系统中就是创建进程

创建进程的系统调用叫fork。这个名字很奇怪,中文叫“分支”。为啥启动一个新进程叫“分支”呢?

在 Linux 里,要创建一个新的进程,需要一个老的进程调用 fork 来实现,其中老的进程叫作父进程(Parent Process),新的进程叫作子进程(Child Process)。

  1. 调用fork创建进程,子进程将各个子系统为父进程创建的数据结构也全部拷贝了一份,甚至连程序代码也是拷贝过来的
  2. 对于fork系统调用的返回值进行判断,0(子进程),子进程的进程号(父进程)
  3. 如果是父进程,接着做原来应该做的事情,如果是子进程需要请求另一个系统调用execve来执行另一个程序,这个时候,子进程和父进程就彻底分道扬镳了,也即产生了一个分支(fork)了。

先后顺序

新进程都是父进程 fork 出来的,那到底谁是第一个呢?

​ 启动的时候先创建一个所有用户进程的“祖宗进程”。这个在讲系统启动的时候还会详细讲,我这里先不多说。有时候,父进程要关心子进程的运行情况,这毕竟是自己身上掉下来的肉。有个系统调用waitpid,父进程可以调用它,将子进程的进程号作为参数传给它,这样父进程就知道子进程运行完了没有,成功与否。所以说,所有子项目最终都是老板,也就是祖宗进程 fork 过来的,因而它要对整个公司的项目执行负最终的责任。

内存管理

在操作系统中,每个进程都有自己的内存,互相之间不干扰,有独立的进程内存空间,在内存空间里面我们会放上程序代码(代码段),对于进程的内存空间来讲,放进程运行中产生数据的这部分,我们称为数据段。其中局部变量的部分,在当前函数执行的时候起作用,当进入另一个函数时,这个变量就释放了;也有动态分配的,会较长时间保存,指明才销毁的,这部分称为(Heap)

内存是需要的时候再分配(虚拟内存和物理内存的分配是不同的)虚拟内存是程序启动的时候就分配的,但是物理内存是真的写入数据的时候,发现没有对应物理内存,才会触发一个中断,现分配物理内存。

在堆里面分配内存的系统调用

brk

当分配的内存数量比较小的时候,使用 brk,会和原来的堆的数据连在一起,这就像多分配两三个工位,在原来的区域旁边搬两把椅子就行了

mmap

当分配的内存数量比较大的时候,使用 mmap,会重新划分一块区域,也就是说,当办公空间需要太多的时候,索性来个一整块。

文件管理

文件管理的六个系统

  • 对于已经有的文件
    • 可以使用open打开这个文件
    • close关闭这个文件;
  • 对于没有的文件,可以使用creat创建文件;
  • 打开文件以后,可以使用lseek跳到文件的某个位置;
  • 可以对文件的内容进行读写
    • 读的系统调用是read
    • 写是write

Linux一切皆文件

  • 启动一个进程,需要一个程序文件,这是一个二进制文件
  • 启动的时候,要加载一些配置文件,例如 yml、properties 等,这是文本文件;启动之后会打印一些日志,如果写到硬盘上,也是文本文件
  • 但是如果我想把日志打印到交互控制台上,在命令行上唰唰地打印出来,这其实也是一个文件,是标准输出stdout 文件
  • 这个进程的输出可以作为另一个进程的输入,这种方式称为管道,管道也是一个文件。
  • 进程可以通过网络和其他进程进行通信,建立的Socket,也是一个文件。
  • 进程需要访问外部设备,设备也是一个文件。
  • 文件都被存储在文件夹里面,其实文件夹也是一个文件。
  • 进程运行起来,要想看到进程运行的情况,会在 /proc 下面有对应的进程号,还是一系列文件。

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

所以说,文件操作是贯穿始终的,这也是“一切皆文件”的优势,就是统一了操作的入口,提供了极大的便利。

文件描述符

异常处理和信号处理

信号分为以下几种

  • 在执行一个程序的时候,在键盘输入“CTRL+C”,这就是中断的信号,正在执行的命令就会中止退出;
  • 如果非法访问内存,例如你跑到别人的会议室,可能会看到不该看的东西;
  • 硬件故障,设备出了问题,当然要通知项目组;
  • 用户进程通过kill函数,将一个用户信号发送给另一个进程。

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

提供了信号处理服务,项目执行过程中一旦有变动,就可以及时处理了。

进程间通信

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

当两个项目组需要交互的信息比较大的时候,可以使用共享内存的方式,也即两个项目组共享一个会议室(这样数据就不需要拷贝来拷贝去)。大家都到这个会议室来,就可以完成沟通了。这时候,我们可以通过shmget创建一个共享内存块,通过shmat将共享内存映射到自己的内存空间,然后就可以读写了

但是,两个项目组共同访问一个会议室里的数据,就会存在“竞争”的问题。如果大家同时修改同一块数据咋办?这就需要有一种方式,让不同的人能够排他地访问,这就是信号量的机制Semaphore

这个机制比较复杂,我这里说一种简单的场景。(也就是所谓的加锁)

对于只允许一个人访问的需求,我们可以将信号量设为 1。当一个人要访问的时候,先调用sem_wait。如果这时候没有人访问,则占用这个信号量,他就可以开始访问了。如果这个时候另一个人要访问,也会调用 sem_wait。由于前一个人已经在访问了,所以后面这个人就必须等待上一个人访问完之后才能访问。当上一个人访问完毕后,会调用sem_post将信号量释放,于是下一个人等待结束,可以访问这个资源了。

网络通信

不同机器的通过网络相互通信,要遵循相同的网络协议,也即TCP/IP 网络协议栈。Linux 内核里有对于网络协议栈的实现。

网络服务是通过套接字 Socket 来提供服务的。Socket 这个名字很有意思,可以作“插口”或者“插槽”讲。虽然我们是写软件程序,但是你可以想象成弄一根网线,一头插在客户端,一头插在服务端,然后进行通信。因此,在通信之前,双方都要建立一个 Socket。

我们可以通过 Socket 系统调用建立一个 Socket。Socket 也是一个文件,也有一个文件描述符,也可以通过读写函数进行通信

中介与 Glibc

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

Glibc内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值