admin 管理员组文章数量: 887021
系列文章目录
服务器开发系列(一)——计算机硬件
服务器开发系列(二)——Jetson Xavier NX
文章目录
- 系列文章目录
- 前言
- 一、操作系统概述
- 二、Linux和Windows的应用场景
- 三、系统开机流程
- 四、文件操作
- 五、vim编辑器
- 六、Shell脚本
- 七、账号与权限管理
- 八、系统进程
- 九、系统服务
- 十、工作排程
- 十一、登录文件
- 十二、数据备份
- 十三、函数链接库
- 总结
- 参考资料
前言
操作系统是服务器开发的基础,这里基于Linux相关书籍中的知识体系,对Linux系统的基础功能进行了梳理,并参照对比给出Windows系统的相关情况。
这里使用的Linux系统是Ubuntu18.04,Windows系统是Win10家庭版。
一、操作系统概述
目前的计算机系统将软件分为两大类,一类是系统软件,一类是应用软件。为了使人可以和机器沟通,计算机科学家会开发出人类看得懂的编程语言,再创造一种编译程序将这些人类能够写和看的程序语言转译为机器能看得懂的机器码,如此一来人类修改与撰写程序就容易多了。机器能读懂的语言是汇编语言,而常用的编程语言有C/C++、Java、Python等。
操作系统Operating System其实也是一组程序,这组程序的重点在于管理计算机的所有活动以及驱动系统中的所有硬件。计算机没有软件只是一堆废铁,操作系统的功能就是让CPU可以开始判断逻辑与运算数值,让内存可以加载/读出数据与程序代码,让硬盘可以被存取,让网卡可以传输数据,让所有周边可以开始运转等。总之硬件的所有动作都必须要透过这个操作系统来达成。
上述功能就是操作系统的内核Kernel!你的计算机能不能做某些事情都与内核有关。只有内核可提供的功能,计算机系统才能帮你完成。例如你的内核不支持TCP/IP网络协议,那么无论购买了什么样的网卡,该内核都无法提供网络能力!但是单有内核我们使用者也不知道能做啥事,因为内核主要在管控硬件与提供相关的能力(例如存取硬盘、网络功能、CPU资源取得等),这些管理的动作是非常重要的,如果使用者能够直接使用内核的话,如果用户不小心将内核程序停止或破坏,将会导致整个系统的崩溃!因此内核程序所放置到内存当中的区块是受保护的,并且开机后就一直常驻在内存当中。所以如果系统只有内核的话,我们就只能看着已经准备好运作Ready的计算机系统却无法操作它,这时就需要软件的帮忙了。
既然硬件都是由内核管理,那么如果想要开发软件的话,自然就得要去参考这个内核的相关功能。为了解决这个问题,操作系统通常会提供一整组的开发接口给工程师来用,工程师只要遵循这些开发接口就很容易开发软件了。例如我们用C语言开发程序,不需要再去考虑内核的相关功能,因为内核的系统呼叫接口会主动的将C语言的相关语法转换成内核可执行的任务函数,该内核就能够顺利运作程序了。
为了减少系统调用的开销,随着时间的推移,Linux内核中引入了两种机制:vsyscall(虚拟系统调用)和vDSO动态共享对象),原来的vsyscall机制现在已经过时。两种机制的目的是相同的:允许系统调用而不需要上下文切换。这种机制背后的基本原理是,一些经常使用的系统调用实际上并不需要内核权限,因此将这些操作的控制权交给内核是不必要的开销。顾名思义,这些调用是在一个特殊的动态共享库(linux-vdso.so)中实现的,该库由内核自动提供给任何创建的进程。
软件与内核有比较大的关系,而与硬件关系不大;硬件与内核有比较大的关系;用户则与应用程序有关。
在定义上,只要能够让计算机硬件正确无误运作的就算是操作系统。所以说操作系统其实就是内核与其提供的接口工具,不过内核缺乏与用户沟通的亲和接口,所以目前我们提到操作系统时,都会包含内核与相关的用户应用软件。
既然内核主要是在负责整个计算机系统相关的资源分配与管理,那么其实整部计算机系统最重要的就是CPU与内存。因此内核至少要有以下功能:
①系统呼叫接口System call interface:其是为了方便程序开发者可以轻易的透过与内核的沟通,将硬件资源进一步利用;
②进程管理Process control:一部计算机可能同时有很多工作要CPU运算处理,内核这时必须要能够控制这些工作,让CPU的资源作有效分配才行。良好的CPU排程机制(就是CPU先运行哪个工作的排列顺序)将会有效加快整体系统效能;
③内存管理Memory management:控制整个系统的内存管理是非常重要的,因为系统所有的程序代码与数据都必须先存放在内存中。通常内核会提供虚拟内存功能,当内存不足时可以提供内存置换swap功能;
④文件系统管理Filesystem management:例如数据的输入输出,不同文件格式的支持等工作都是文件系统管理,如果你的内核不认识某个文件系统,那么你将无法使用该文件格式的文件。例如Windows98不认识NTFS格式的硬盘;
⑤装置的驱动Device drivers:硬件的管理是内核的主要工作之一,装置的驱动程序就是内核需要做的事情,现在有可加载模块功能,其将驱动程序编译成模块,从而简化内核的编译。不过驱动程序是由硬件厂商提供的,与操作系统开发者无关。
理论上,随着Linux内核将传统操作系统的职责转移到用户空间代码,其架构越来越类似于微内核操作系统。即文件系统和内存管理是独立的进程,在内核之外运行,I/O驱动程序也是独立的进程(在内核中,但只是因为英特尔CPU的脑死亡特性,否则很难做到这一点)。历史上对Linux的批评是它过于单一,无法扩展和生存。Torvalds当时直接解决了这些批评,并在以后反思了他的设计原则。
Linux是一套操作系统,就是内核与系统呼叫接口那两层。Linux的版本可分为发展版development和稳定版stable两种。如果你想用Linux核心来开发你的系统,必须要选择长期支持的稳定版才行!为了让使用者能够接触到Linux,于是很多商业公式或团体将Linux Kernel(含tools)与可运行的软件整合起来,加上自己具有创意的工具程序,这个Kernel+Softwares+Tools+工具程序的东西称为Linux distribution,翻译为Linux发布套件。Linux核心版本与distribution版本并不相同,如果你需要在网上提问时,最好说明distribution版本号。以Ubuntu这个distribution为例,则应该说所用的Linux是Ubuntu其distribution版本为18.x。
Linux distribution主要分为两大类系统:一种是使用rpm方式安装软件的系统,包括Red Hat,Fedora,SuSE等;一种是使用dpkg方式安装软件的系统,包括Debian,Ubuntu,B2D等。若是加上商业公司或社群单位的分类,可以形成以下表格:
虽然每个Linux distribution的差异性并不大,但还是应依据计算机的用途来选择:
①用于企业环境:建议使用商业版本,例如Red Hat的RHEL或SuSE都是不错的选择。毕竟企业环境强调的是永续的经营,由于商业版本都会提供客户服务,所以可以降低企业风险;
②用于个人或交线的服务器环境:如果你的服务器在所在环境宕机不会造成太大问题的话,可以使用号称完全兼容商业版RHEL的CentOS,因为CentOS是抓RHEL的源码来进行修改的一个Linux distribution,号称兼容于RHEL,适合于服务器系统环境;
③用于个人的桌面计算机:如果想要尝鲜,Fedora或Ubuntu等桌面环境版本是不错的选择。
由于Linux系统使用了异步的磁盘/内存数据传输模式,同时又是一个多人多任务的环境,所以与Windows系统最大的差别是不能随意不正常关机,关机是有一定的程序的,错误的关机方法可能会造成磁盘数据的损毁!所以在工业应用场景,一定要给Linux系统的服务器配备UPS电源!
二、Linux和Windows的应用场景
由于Linux kernel实在是非常的小巧精致,可以在很多强调省电以及较低硬件资源的环境底下执行;此外由于Linux distribution整合了非常多很棒的软件(包括专利软件和自由软件),所以也相当适合个人计算机使用;另外近几年很流行的云计算环境也成了Linux的强势着力点!不同的单位对于数字化有不同的目标,所以针对Linux的各项优点,在许多领域都得到广泛应用:
①网络服务器:网络服务器是Linux当前最热门的应用。由于承袭了Unix高稳定性的良好传统,Linux上面的网络功能特别稳定和强大,且在Linux上的服务器软件几乎都是自由软件,因此作为一部网络服务器,例如WWW、Mail Server、File Server等Linux绝对是上上之选!
②关键任务的应用(金融数据库、大型企业网管环境):目前很多金融企业都已经使用Linux作为它们的关键任务应用,所谓的关键任务就是该企业最重要的业务,例如金融业最重要的就是投资者、账户的数据了,这些数据大多使用数据库系统来作为存取接口。由于这些数据很重要,强调程序在数据库、安全强化方面的应用效能,金融企业就使用Linux来完成这些任务;
③学术机构的高效能运算任务:例如工程界流体力学的数值模式运算,娱乐业的特效功能处理,软件开发者的工作平台等,需要强大的运算能力。由于Linux的创造者本身是个计算机性能癖,所以Linux有强大的运算能力,并且Linux具有支持度相当广泛的gcc编译软件,因此其在这方面的优势可是相当明显的。此外为了加强整体系统的效能,计算机集群的并行运算能力在近年来一直是研究的重点。所谓的并行运算指的是将原本的工作分成多份,然后交给多部主机去运算,最终再将结果收集起来的一种方式。由于通过高速网络使用多部主机,能够让原本需要很长运算时间的工作,大幅降低等待时间。Linux系统就是这种架构下的相当重要的环境平台!
④手持系统(手机、PDA):Android其实就是Linux核心的一支,其专门用于针对手机/平板这类的ARM机器所设计;
⑤嵌入式系统:包括路由器、防火墙、路由器、交换机、机器人控制芯片、家电产品的微控制器都可以使用Linux系统。但开发嵌入式系统必须很熟悉Linux kernel与驱动程序的结合才行,这方面的学习就不那么简单了;
⑥云计算:许多大型互联网公司ISP提供所谓的公有云,来让企业用户或个人用户使用ISP的虚拟化产品,这些虚拟化后的系统经常就是Linux。所以说云程序的底层就是Linux,搭建的虚拟机环境内容也是Linux系统。
⑦物联网边缘端设备:由于运算资源可以集中在云环境中,所以联机到云环境的设备需要轻量化。近来很流行的树莓派等单板式计算机很适合作为轻量化的边缘端设备的载体,其上运行的系统也是Linux。
Windows系统相比于Linux最主要的优点是:系统生态好,就是用的人多、可选软件多、硬件和维修支持也多;
其主要缺点是:稳定性差、硬件利用率差、网络安全性差。
所以Windows系统主要用于个人电脑,而在服务器、科学计算、人工智能领域则只推荐使用Linux系统。
三、系统开机流程
目前的计算机系统在加载硬件驱动方面的程序,主要有早期的BIOS与新的UEFI两种机制,现在基本上都是UFEI了。基于BIOS的整个开机过程如下:
①BIOS是在开机时计算机系统主动执行的第一个程序,BIOS会去分析计算机里面有哪些存储设备,BIOS会依据使用者的设定去取得能够开机的磁盘,并到该磁盘里面去读取第一个扇区的MBR位置,该处会放置最基本的开机管理程序,即grub2这个boot loader程序;
②接下来MBR会启动开机管理程序Boot Loader,开机管理程序是一支可读取内核文件来执行的软件,其目的是加载内核文件;
③接下来内核文件开始工作,Boot Loader和BIOS就功成圆满,内核文件开启操作系统的各项功能,操作系统正式运行。内核会主动呼叫systemd程序,并以default.target流程开机。
UEFI主要是想取代BIOS的固件界面,其使用C语言编写,比使用汇编语言的BIOS更容易开发。由于使用C语言开发,如果开发者够厉害,甚至可以在UEFI开机阶段就让系统通过TCP/IP直接上网,而不需要进入操作系统,这让小型系统的开发充满各种可能性!。传统的BIOS与UFEI的差异如下表所示:
UEFI就像是一个低阶的操作系统,其连主板上面的硬件资源管理也跟操作系统相当类似,只需加载驱动程序即可控制操作。同时由于程序得宜,使用UEFI驱动的主机在开机速度上要比BIOS的快上许多。
UEFI系统的启动流程遵循PI Spec。其从上电到关机可以分为7个阶段:
SEC(安全验证)->PEI(EFI前期初始化)->DXE(驱动执行环境)->BDS(启动设备选择)->TSL(操作系统加载前期)->RT(系统系统运行阶段)->AL(系统灾难恢复期或关机)
①SEC阶段:其会做一些与硬件相关的验证,并将控制权交给PEI;
②PEI阶段:所能使用的资源十分有限,会初始化内存,主要功能是初始化一些硬件设备,并给DXE准备执行环境,通过HOB传递给DXE,最终将控制权交给DXE;
③DXE阶段:内存已经完全可用,主要负责初始化一系列服务,例如BootServices/RuntimeServices/DxeServices,安装ConfigurationTable,分发DXE Drivers,初始化一些Protocol并安装Binding Driver为后续使用;
④BDS阶段:主要负责执行可启动策略,包括初始化控制台设备,加载设备相关驱动,为BIOS Setup做准备,根据系统设置加载和启动可启动选项;
⑤TSL阶段:载入并开始grub镜像,资源由UEFI kernel提供,当grub调用ExitBootServices后就进入系统Runtime阶段;
⑥RT阶段:控制权完全交给OS,保留RuntimeServices给OS使用,MM Mode脱离OS独立运行;
⑦AL阶段:在该阶段如果遇到灾难性错误,固件提供错误处理机制和灾难恢复机制。
由于X Window图形界面只是Linux的一组软件不是Linux核心,目前发展出来的X Window对于系统的管理上还是有无法掌握的地方。所以以Linux为操作系统的环境,大部分时间都是工作在命令模式下的,即主要操作的是Bash Terminal。甚至对于服务器或者嵌入式系统,因为其目的是提供客户端来联机的,并不是让使用者直接在这部服务器上面按鼠标或键盘操作的,是不会安装或启动X Window的,因为X Window通常会吃掉很多系统资源。所以本博文以及后续服务器开发相关内容基本上都是围绕命令模式展开的。
四、文件操作
Linux虚拟文件系统VFS是一个内核抽象层。关键思想是VFS定义了所有具体文件系统都必须实现的通用文件系统API。在软件设计模式方面VFS充当代理层。所有与文件相关的系统调用都被定向到VFS,然后它将每个调用重定向到适当的具体底层文件系统。
Linux提供了一个统一文件系统的抽象,它具有一个根目录,所有其他文件和目录都可以从该根目录中访问。事实上,VFS集成了许多不同的文件系统,这些文件系统在不同的挂载点被合并到统一的目录层次结构中。检查/etc/mtab以查看当前挂载的文件系统、它们的具体文件系统类型以及它们在统一层次结构中的位置。伪文件/proc/filesystems维护Linux内核支持的文件系统列表。请注意,nodev标志表示文件系统未与物理设备关联。相反,此类文件系统上的伪文件是由内核维护的内存数据结构合成的。一个具体的文件系统通过register_filesystem调用注册到VFS。提供的参数是一个file_system_type,它提供了一个名称、一个用于获取文件系统超级块的函数指针和一个next指针。所有file_system_type实例都组织为一个链表。fs/filesystems.c中的全局变量file_systems指向这个链表的头部。在这种情况下,超级块是包含关键文件系统元数据的内存数据结构。每个挂载的设备对应一个超级块实例。其中一些数据来自磁盘(其中可能有一个文件系统块,也称为超级块)。其他信息,特别是名为struct super_operations的函数指针向量,直接从具体的文件系统代码库中填充。
超级块处理整个文件系统的VFS交互。使用称为inode和dentries的结构处理单个文件。
inode是一个VFS级别的内存数据结构。其他Unix操作系统将这些结构称为vnode。具体的文件系统可能有专门的inode版本。例如,将include/linux/fs.h中的VFS struct inode定义与fs/ext4/ext4.h中的ext4变体struct ext4_inode和struct ext4_inode_info进行比较。
事务记录以原子方式快速添加到日志中。日志文件实际上是一个循环缓冲区,因此旧条目在填满时会被覆盖。检查文件/proc/fs/jbd2/ /info以查看有关日志中事务条目数的统计信息。
Linux内的所有数据都是以文件形式呈现的。Linux和其他类似UNIX的操作系统的一个关键特征是经常被引用的“一切皆文件”的概念并不意味着Linux中的所有对象都是上面定义的文件,而是Linux更喜欢使用一致的接口处理,OS可以从中读取数据或向其写入数据的所有对象。所以说**“一切都是字节流”可更准确说明Linux使用文件描述符的概念**。这是一个抽象句柄,用于访问输入/输出资源(文件只是其中的一种类型)。所以我们可以说,在Linux中一切都是文件描述符。
整个Linux系统最重要的地方就是目录树架构。目录树架构directory tree就是以根目录为主,然后向下呈现分支状的目录结构的一种文件架构,整个目录树架构最重要的就是根目录root directory,其被表示为/,所有的文件都与目录树有关。
挂载就是将一个目录当成进入点,将磁盘分区的数据放置在该目录下,即进入该目录就可以读取该分区的意思,进入点的目录我们称为挂载点。由于整个Linux系统最重要的是根目录,因此根目录一定需要挂载到某个分区的,至于其他的目录则可依用户自己的需求来给予挂载到不同的分区。
注意:Windows也是用挂载的概念,当你将U盘插入到Windows主机时,系统会检测到一个F盘,如果想读取U盘的数据就去F盘找。同样这枚U盘插入另一台Windows主机时,显示的就是H盘了。这个装置与磁盘对应的关系就是Windows下的挂载。
在Linux系统中,根据档名写法的不同可将路径path定义为绝对路径与相对路径:
①绝对路径:由根目录/开始写起的文件名或目录名称,例如/home/dmtsai/.bashrc;
②相对路径:相对于当前路径的文件名写法,例如./home/dmtsai或…/…/home/dmtsai。
Windows系统的路径也分为绝对路径与相对路径,基本与Linux系统相同,只是cd命令不能跨盘符操作,即不能通过cd从C盘目录到D盘目录,而是通过“盘符:”;路径间的分隔符不是/而是\。
使用$ ls -al命令可列出所有文件详细的权限与属性,包括隐藏文件。(隐藏文件就是文件名第一个字符为“.”的文件)
其中:
①第一栏代表这个文件的类型与权限:这一栏共有10个字符:
<1>第一个字符代表这个文件是目录、文件或链接文件等:
<2>接下来的字符中以3个为一组,且均为rwx的三个参数的组合,其中r表示可读、w表示可写,x表示可执行。注意:这3个权限的位置不会改变,如果没有权限就只会是减号-:
(1) 第一组为文件拥有者可具备的权限;
(2) 第二组为加入此群组账号的权限;
(3) 第三组为非本人且没有加入本群组的其他账号的权限。
②第二栏表示有多少档名连接到此节点i-node:这个属性记录的就是有多少不同的档名连接到相同的一个i-node号码去就是了;
③第三栏表示这个文件(或目录)的拥有者账号;
④第四栏表示这个文件的所属群组:Linux系统下你的账号会加入一个或多个群组中;
⑤第五栏为这个文件的容量大小,默认单位为bytes;
⑥第六栏为这个文件的建档日期或者是最近的修改日期;
⑦第七栏为这个文件的档名。
Linux包含的文件种类有:
①正规文件:就是一般我们在进行存取类型的文件,ls列出属性中的第一个字符为-;
②目录:ls列出属性中的第一个字符为d;
③连结档:类似Windows系统下的快捷方式,ls列出属性中的第一个字符为l;
④设备与装置文件:与系统周边及存储等相关的一些文件,通常都集中在/dev这个目录下,通常又分为两种:
<1>区块设备档:就是一些存储数据,以提供系统随机存取的接口设备,硬盘与软盘等就是,ls列出属性中的第一个字符为b;
<2>字符设备文件:一些串口接口的设备,键盘与鼠标就是,ls列出属性中的第一个字符为c。
⑤资料接口文件:其通常被用在网络上的数据承接,最常在/run或/tmp目录中看到这种文件,ls列出属性中的第一个字符为s;
⑥数据输送文件FIFO:其主要目的在于解决多个程序同时存取一个文件所造成的错误问题,ls列出属性中的第一个字符为p。
对应Windows系统中文件的定义,是实际含有数据的地方,仅包括一般的文本文件、数据库内容文件、二进制可执行文件等。
Linux将文件可存取的身份分为三个类别,分别为owner/group/others,且三种身份各有read/write/execture权限。用户与群组的功能是相当健全而好用的一个安全防护机制。
①改变文件所属群组的命令:chgrp
②改变文件拥有者的命令:chown
③改变文件权限的命令:chmod
在修改权限时,可以使用数字来代表各个权限:r: 4,w: 2,x: 1。其对应的含义为:
①r:可读取此文件的实际内容,如读取文本文件的文字内容;
②w:可以编辑、新增或者修改该文件的内容(但不包含删除该文件);
③x:该文件具有可以被系统执行的权限。
每种身份(owner/group/others)各自的三个权限(r/w/x)分数是需要累加的,例如当权限为 -rxwrwx—则对应的分数为:
①owner = rwx = 4+2+1 = 7
②group = rwx = 4+2+1 = 7
③others = — = 0+0+0 = 0
于是该文件的权限数字就是770了,其对应的chmod示例命令为:
$ chmod 770 .bashrc
Linux的文件是没有扩展名的,其能否被执行与它第一栏的第十个属性有关。具有可执行的权限与具有可执行的程序代码是两回事。能不能执行成功,关键还是看该文件的内容!不过我们仍然希望可以借助扩展名来了解该文件是什么东西,因此常用的扩展名有:
①*.sh:脚本或批处理文件scripts,是用shell写成的;
②Z,.tar,.tar.gz,.zip,.tgz:经过打包的压缩文件;
③.html,*.php:网页相关文件,.html文件可使用网页浏览器来直接开启,.php文件则可以透过client端的浏览器来浏览。
而在Windows下一个文件是否具有执行的能力是由扩展名来判断的,例如可执行文件有.exe、.bat、等。
目录主要的内容在记录文件名列表,文件名与目录有强烈的关联:
①r:表示具有读取目录结构列表的权限,所以当一个目录具有读权限时,表示你可以查询该目录下的文件名数据,于是你能利用ls命令将该目录的内容列表显示出来;
②w:表示你具有改动该目录结构列表的权限,也就是可以:
<1>建立新的文件与目录;
<2>删除已经存在的文件与目录(不论该文件的权限为何);
<3>将已存在的文件或目录进行更名;
<4>移动该目录内的文件、目录位置。
③x:表示用户能否进入该目录成为工作目录,所谓的工作目录work directory就是你当前所在的目录。
要开放目录给任何人浏览时,应该至少给予r和x的权限,但w权限不能随便给。
在Linux系统下你的账号会加入一个或多个群组中,例如class1,class2,class3均属于projecta群组,假设某个文件所属的群组为projecta,且该文件的权限为-rwxrwx—,则class1,class2,class3三人对于该文件都具有可读、可写、可执行的权限(看群组权限);但如果是不属于projecta的其他账号,对于此文件就不具有任何权限了。群组最有用的功能之一就是当你在团队开发时资源的受限共享应用。
Linux系统中每个文件都有3个时间:
①mtime:内容数据改动时才更新的时间;
②ctime:文件的权限或属性改动时才更新的时间;
③atime:文件内容被取用access时才更新的时间。
例如:
$ ls -lc filename # 列出文件的 ctime
$ ls -lu filename # 列出文件的 atime
$ ls -l filename # 列出文件的 mtime
命令$ touch [-acdmt] ,-a仅修改访问时间;-c仅修改文件属性时间;-d修改文件日期;-m仅修改mtime时间;-t修改文件时间[yymmddhhmm]。
在Windows系统中:
①查看目录下文件情况使用dir命令;
②文件和文件夹可设置:隐藏与否、只读与否,是否可执行取决于扩展名(即文件类型);
③文件和文件夹也可通过“属性”→“安全”设置账号和群组权限,权限也对应rwx;
④文件和文件夹有3个时间:创建时间、修改时间、访问时间。
文件系统层次标准FHS依据文件系统使用的频繁与否和是否允许使用者随意改动,将目录定义为四种交互作用的形态:
FHS要求Linux中必须存在的目录有:
①/:根目录;
②/bin:放置的是在单人维护模式下还能够被操作的命令,在/bin底下的命令可以被root与一般账号所使用;
③/boot:主要放置开机会使用到的文件,包括Linux核心文件以及开机选单与开机所需配置文件等;
④/dev:任何装置与接口设备都是以文件的型态存在于这个目录当中的,只要透过存取这个目录底下的某个文件,就等于存取某个装置;
⑤/etc:系统主要的配置文件几乎都放置在这个目录内,例如人员的账号密码文件、各种服务的启始档等。一般来说这个目录下的各文件属性是可以让一般使用者查阅的,但是只有root有权力修改;
⑥/lib:其放置的是在开机时会用到的函数库,以及在/bin或/sbin下的命令会呼叫的函数库;
⑦/media:其放置的是可移除的装置;
⑧/mnt:如果想要暂时挂载某些额外的装置,例如U盘,建议放置在这个目录中;
⑨/opt:是第三方辅助软件放置的目录,如果你想自行安装额外的软件(非distribution提供的)也可以放到这个目录;
⑩/run:放置开机后所产生的各项信息;
⑪/sbin:放置开机过程中所需要的命令,包括开机、修复、还原系统的命令;
⑫/srv:其放置一些网络服务启动后所需要取用的数据目录;
⑬/tmp:其是一般用户或者正在执行的程序暂时放置文件的地方,这是任何人都能够存取的,所以需要定期的清理。重要数据是不可放置在此目录的;
⑭/usr:与软件安装/执行有关,类似于Windows系统的C:\Windows\当中的一部分+C:\Program files\;
⑮/var:与系统运作过程有关,主要放置变动性数据。
FHS建议Linux中应该存在的目录有:
①/home:这是系统默认的用户家目录。当你新增一个一般使用者账号时,默认的用户家目录都会规范到这里;
②/lib:用来存放与/lib不同格式的二进制函数库,例如支持64位的/lib64函数库;
③/root:系统管理员(root)的家目录,之所以放在这里是因为如果进入单人维护模式而仅挂载根目录时,该目录就能够拥有root的家目录,所以我们会希望root的家目录与根目录放置在同一个分区中;
④/lost+found:其是使用标准的ext2/ext3/ext4文件系统格式才会产生的一个目录,目的在于当文件系统发生错误时将一些遗失的片段放置到这个目录下。不过如果使用的是xfs文件系统的话,就不会存在这个目录;
⑤/proc:这个目录本身是一个虚拟文件系统(virtual filesystem),它放置的数据都是在内存当中,例如系统内核、进程信息process、周边装置的状态及网络状态等。因为这个目录下的数据都是在内存当中,所以本身不占任何硬盘空间!比较重要的文件例如:/proc/cpuinfo, /proc/dma, /proc/interrupts, /proc/ioports, /proc/net/*等;
⑥/sys:这个目录跟/proc非常类似,也是一个虚拟的文件系统,主要也是记录内核与系统硬件信息较相关的信息,包括目前已加载的内核模块与内核侦测到的硬件装置信息等。
Linux中的环境变量是PATH,当我们执行一个命令时,例如ls,系统会依照PATH的设定去每个PATH定义的目录下搜寻文件名为ls的可执行文件,如果在PATH定义的目录中含有多个文件名为ls的可执行文件,那么先搜寻到的同名命令先被执行。例如:
$ echo $PATH
>>> /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
环境设置文件有两种:系统环境设置文件和个人环境设置文件。
①系统中的用户工作环境设置文件有:
<1>登录环境设置文件:/etc/profile
<2>非登录环境设置文件:/etc/bash.bashrc
②用户个人设置的环境设置文件有:
<1>登录环境设置文件:~/.profile # 这是环境变量设置的地方
<2>非登录环境设置文件:~/.bashrc # 这是定义别名的地方
①登录环境:指用户登录系统后的工作环境;
②非登录环境:指用户在调用子Shell时所使用的用户环境。
当要修改环境变量PATH内包含的目录时有多种方法,例如添加/etc/apache/bin:
①# vi /etc/profile;在适当位置添加PATH=$PATH:/etc/apache/bin(注意:=两边不能有任何空格)。
②# vi ~/.bashrc;修改PATH行,把/etc/apache/bin添加进去,这种方法是针对用户起作用的。这种方法最好,因为其修改的是当前用户的全局设置。
注意:想改变PATH必须重新登陆才能生效,或者通过命令:
$ source profile
(source /etc/profile)重新执行一次/etc/profile shell脚本来进行刷新。
Windows系统可通过“设置”→“高级系统设置”→“环境变量”来设置环境变量,多个环境变量之间的分隔符是“;”。
五、vim编辑器
Linux系统中预装有多个文本编辑器,例如gedit和vim。gedit类似于Windows系统中的Notepad,比vim更好用,但由于部分Linux软件默认是调用vim进行编辑功能的,所以vim编辑器的基础使用功能是Linux系统操作所必学的。
vim编辑器有2种操作模式:普通模式和插入模式。当打开要编辑的文件时(或新建一个文件时),vim会进入普通模式。在普通模式下vim会将按键解释成命令;在插入模式下vim会将当前光标位置输入的每个键都插入到缓冲区。按下i键就进入插入模式,按下Esc键就从插入模式退回到普通模式。
vim在普通模式下有个特别的功能叫命令行模式,命令行模式提供了一个交互式命令行,可以输入额外的命令来控制vim的行为。要进入命令行模式在普通模式下按:键。在命令行模式下的命令有:
①q 如果为修改缓冲区数据则退出;
②q! 取消所有对缓冲区数据的修改并退出;
③w filename 将文件保存到另一个文件中;
④wq 将缓冲区数据保存到文件并退出;
在普通模式下vim提供了一些命令来编辑缓冲区中的数据:
①x 删除当前光标所在位置的字符;
②u 撤销前一编辑命令;
③a 在当前光标后追加数据。
六、Shell脚本
shell是一种人机交互的接口,提供使用者使用界面的软件是一种命令解析器,是Linux内核的一个壳,负责外界与Linux内核的交互。Windows的cmd也是一种shell。用户在shell中提交命令,shell负责接收用户的命令并扮演命令解析器的角色。当你打开一个terminal时操作系统会将terminal和shell关联起来,当我们在terminal中输入命令时shell就负责解析命令。bash是GNU计划中重要的工具软件之一,也是Linux distributions的标准shell。bash主要的优点有:
①能记忆使用过的命令;
②按tab键可以命令补全;
③可以给命令设定别名;
④工作控制、前景背景控制;
⑤程序化脚本;
⑥支持通配符来帮助用户查询与命令下达。
通过type这个命令我们可以知道每个命令是否为bash的内建命令。
在shell变量的设定当中,单引号与双引号的最大不同在于双引号仍然可以保有变量的内容,但单引号内仅能是一般字符,而不会有特殊符号。
用env观察环境变量与常见环境变量说明:
$ env
用set观察所有变量 (含环境变量与自定义变量):
$ set
如果想要让该变量内容继续的在子程序中使用就输入:
$ export 变量名称
shell script是利用shell的功能所写的一个程序,这个程序是纯文本文件,将一些shell的语法与命令(含外部命令)写在里面,搭配正规表示法、管线命令与数据流重导向等功能,以达到我们所想要的处理目的。但shell script的速度较慢,且使用的CPU资源较多,造成主机资源的分配不良。C语言是编译型的,而shell script是解释型的。
在编写的shell script文本中内容必须以#!/bin/bash开头,其意思是告诉执行器需要调用/bin/bash来执行这个脚本。脚本必须要有可执行权限,可通过命令:
$ chmod u+x XXX.sh #增加x执行权限
shell script中变量定义的语法有:
①定义变量:变量=值 注意:等号左右不能有空格
②撤销变量:unset 变量名
③静态变量:readonly 变量=值 注意:静态变量不能撤销
注意:变量名可以由字母、数字、下划线组成,但不能以数字开头;变量名一般习惯大写。
例如:
# 定义变量A
A=100
# 使用变量需要给变量加$符号
echo A=$A
echo “A=$A”
# 撤销变量A
unset A
echo “A=$A”
# 定义静态变量B
readonly B=200
echo “B=$B”
上述脚本的运行结果为:
>>> A=100
>>> A=100
>>> A=
>>> B=200
环境变量又叫全局变量,也就是在其他的shell script文件中可以直接引用这个变量。其基本语法为:
①export 变量名=变量值,其将shell变量输出为环境变量/全局变量;
②source 脚本文件,其让修改后的配置信息立即生效;
③$变量名,其获取变量的值。
例如:
# 在脚本文件hello.sh中定义一个环境变量
export JayChou_HOME=/opt/JayChou
# 刷新脚本文件
source /test/hello.sh
# 查询环境变量的值
echo $JayChou_HOME
上述脚本的运行结果为:
>>> /opt/JayChou
当想要在shell scripts中获取执行时指定的参数信息就需要使用位置参数变量,例如sh myshell.sh 100 200 表示执行脚本的同时指定了100、200两个参数,在脚本中使用位置参数变量就可以获取到脚本之外的这两个变量(参数)的值。其基本语法为:
①$n
:n为数字,$0
代表命令本身,$1 - $9
代表第1到第9个参数,第10个及以上的参数需要用大括号包含,如 ${10}
;
②$*
:代表命令行中所有的参数,把所有的参数看成一个整体;
③$@
:代表命令行中所有的参数,把每个参数区分对待,不再是一个整体;
④$#
:代表命令行中所有参数的个数。
例如:
echo “命令本身=$0 第一个参数=$1 地二个参数=$2”
echo “所有的参数=$*”
echo “另一种方式的所有参数=$@”
echoe “参数的个数=$#”
上述脚本的运行结果为:
# ./hello.sh “chi” “zaofan”
>>> 命令本身=hello.sh 第一个参数=chi 第二个参数=zaofan
>>> 所有的参数=chi zaofan
>>> 另一种方式的所有参数=chi zaofan
>>> 参数的个数=2
预定义变量指的是shell scripts编写者事先定义好的变量,可以直接在脚本中使用这些变量。其基本语法为:
①$$
:当前进程的进程号PID;
②$!
:后台运行的最后一个进程的进程号PID;
③$?
:最后一次执行的命令的返回状态:
<1>如果这个变量的值为0,证明上一个命令正确执行;
<2>如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确。
例如:
echo “当前执行的进程id=$$”
# 以后台的方式执行hello.sh脚本
/test/hello.sh & # 以后台方式运行脚本 结尾需要加&符
# 后台运行的最后一个进程的进程号
echo “last_id=$!”
# 最后一次执行命令的执行结果
echo “结果=$?”
上述脚本的运行结果为:
# ./test.sh
>>> 当前执行的进程id=10038
>>> last_id=10039
>>> 结果=0
shell scripts运算符有三种方式:
①变量=$((运算式))
②变量=$[运算式]
③变量='expr 运算式'
注意:使用expr关键字时运算式的运算符两侧要加空格;使用expr做运算时乘法运算必须使用\*
才能实现乘法运算,使用[]则不需要转义。
例如:
# 计算(2+3)*4的值
# 使用方式一
RES1=$(((2+3)*4))
echo “res1=$RES1”
# 使用方式二 这是推荐的
RES2=$[(2+3)*4]
echo “res2=$RES2”
# 使用方式三
TEMP=`expr 2 + 3`
RES3=`expr $TEMP \* 4`
echo “temp=$TEMP”
echo “res3=$RES3”
# 求出命令行的两个整数参数的和 20 50
SUM=$[$1+$2]
echo “sum=$SUM”
上述脚本的运行结果为:
# ./test.sh 20 50
>>> res1=20
>>> res2=20
>>> temp=5
>>> res4=20
>>> sum=70
shell scripts中条件判断的基本语法为:[ 待判断条件 ]
注意:中括号前后必须要有空格;非空返回true,为空返回false。
①字符串比较使用=
②整数比较:小于lt;小于等于le;等于eq;大于gt;大于等于ge;不等于ne
③文件权限判断:有读权限-r;有写权限-w;有执行权限-x
④文件类型判断:文件存在-e;文件存在且是一个常规文件-f;文件存在且是一个文件夹-d
shell scripts流程控制的基本语法为:
①if语句:
<1>单分支:
if [ 待判断条件 ]
then
待执行语句
fi
<2>多分支:
if [ 待判断条件 ]
then
待执行语句
elif [ 待判断条件 ]
then
待执行语句
fi
例如:
# 判断ok是否等于ok
if [ “ok” = “ok” ]
then
echo “equal”
fi
# 判断23是否大于等于22
if [23 -ge 22 ]
then
echo “大于”
fi
# 判断文件是否存在
if [ -f /root/aaa.txt ]
then
echo “存在”
fi
上述脚本的运行结果为:
# ./test.sh
>>> equal
>>> 大于
>>> 存在
②for循环:
<1>基本语法1:
for 变量 in 值1 值2 值3
do
每次循环执行的代码
done
<2>基本语法2:
for ((初始值; 循环条件; 变量变化))
do
每次循环执行的代码
done
例如:
for i in “$*”
do
echo “num is $i”
done
echo “===”
for j in “$@”
do
echo “num is $j”
done
上述脚本的运行结果为:
# ./test.sh 100 200 300
>>> num is 100 200 300
>>> ===
>>> num is 100
>>> num is 200
>>> num is 300
③while循环:
while [ 条件判断式 ]
do
每次循环执行的代码
done
例如:
# 从命令行输入一个数n 统计从1+...+n的值是多少
SUM=0
i=0
while [ $i -le $1 ]
do
SUM=$[SUM+$i]
# i自增
i=$[$i+1]
done
echo “执行结果=$SUM”
上述脚本的运行结果为:
# ./test.sh 10
>>> 执行结果=55
④读取输入:
read [选项] 参数
<1>选项:-p:等待用户输入时的提示内容;-t:指定读取用户输入时等待的时间,如果超过指定的时间则读取内容为空,不再等待;
<2>参数:将用户输入的内容赋值给指定的变量
例如:
# 读取控制台输入的一个NUM1值
read -p “请输入一个数NUM1=” NUM1
echo “你输入的NUM1=$NUM1”
# 读取控制台输入的一个NUM2值 在10秒内输入
read -t 10 -p “请输入一个数NUM2=” NUM2
echo “你输入的NUM2=$NUM2”
上述脚本的运行结果为:
# ./test.sh
>>> 请输入一个数NUM1=8
>>> 你输入的NUM1=8
>>> 请输入一个数NUM2 (超过指定时间未输入)
>>> 你输入的NUM2=
⑤函数
<1>系统函数:
basename:
1)格式:basename 路径 [后缀]
2)功能:返回路径的最后一个/之后的内容(不包括/),一般用于获取文件名
3)如果指定了后缀,则只返回文件的名称不返回文件的后缀
dirname:
1)格式:dirname 路径
2)功能:返回路径的最后一个/之前的内容(不包括/),一般用于获取文件所在路径
例如:
# basename /home/aaa/test.txt
>>> test.txt
# basename /home/aaa/test.txt .txt
>>> test
# dirname /home/aaa/test.txt
>>> /home/aaa
# dirname /home/aaa/bbb/ccc/test.txt
>>> /home/aaa/bbb/ccc
<2>自定义函数:
1)必须在调用函数前先声明函数,shell scripts是逐行执行的;
2)函数定义时不能指定任何形参,也就是必须是空的小括号;
3)return语句只能返回0-255数值之间的整数;
4)如果没有显式声明return语句,则以最后一条命令运行结果作为返回值,0表示执行成功,非0表示执行失败;
5)return语句的返回结果只能通过$?接收;
6)调用函数时不用加函数名后的小括号,只需要在函数名后跟参数即可。
格式1:
function 函数名称()
{
函数内容
[return 整数]
}
# 调用
函数名称 参数1 参数2 ...
格式2:
函数名称()
{
函数内容
[return 整数]
}
# 调用
函数名称 参数1 参数2 ...
注意:当不写function关键字时,函数名后面一定要紧跟小括号,而写了关键字时小括号是可选的。
例如:
# 示例1
getSum()
{
sum=$[$1+$2]
echo “和是=$sum”
}
read -p “请输入一个数n1=” n1
read -p “请输入一个数n2=” n2
getSum $n1 $n2
上述脚本的运行结果为:
# ./test.sh
>>> 请输入一个数n1=10
>>> 请输入一个数n2=90
>>> 和是=100
# 示例2
getResult()
{
return 3
}
getResult
上述脚本的运行结果为:
# ./test.sh
>>> echo $?
>>> 3
在Windows系统的cmd终端中也可以使用shell script,其语法基本与bash shell的相同,主要区别是cmd中运行的脚本是.bat文件。
七、账号与权限管理
虽然登入Linux主机时输入的是账号,但Linux主机并不会直接认识你的账号名称,它仅认识ID,而你的ID与账号就对应保存在/etc/passwd当中。每个登入的使用者至少都会取得两个ID,一个是使用者ID,简称UID,一个是群组ID,简称GID。文件就是利用UID与GID来判断它的拥有者和群组的。当我们要显示文件属性时,系统会根据/etc/passwd与/etc/group的内容,找到UID/GID对应的账号与组名显示出来。
在/etc/passwd文件中,每一行都代表一个账号。需要注意的是,里面很多账号是系统正常运作所使用的,简称为系统账号,例如bin、daemon、adm、nobody等,这些账号不要删除。如下所示:
$ head -n 4 /etc/passwd
>>> root:x:0:0:root:/root:/bin/bash
>>> bin:x:1:1:bin:/bin:/sbin/nologin
>>> daemon:x:2:2:daemon:/sbin:/sbin/nologin
以root系统管理员账号为例,每一行都用:分开,共分8组:
①账号名称:就是登录时输入的账号,用来对应UID;
②密码:因为这个文件的特性是所有程序都能读取,为了避免密码数据被窃取,这个字段的内容仅显示为一个x;
③UID:就是使用者标识符:
<1>0(系统管理员):如果要让其他账号名称也具有root权限时,将该账号的UID改为0即可。也就是说,系统上的管理员不见得只有root,不过很不建议有多个账号的UID是0;
<2>1-999(系统账号):保留给系统使用的ID。由于系统上启动的网络服务或背景服务希望使用较小的权限去运作,因此不希望使用root账号去执行这些服务,所以就要提供这些运作中程序的拥有者账号才行。这些系统账号通常是不可登入的;
<3>1000-60000:给一般使用者使用。
④与③相同;
⑤GID:只是用来规范组名与GID对应而已;
⑥用户信息说明栏:没有什么重要用途,只是用来解释这个账号的意义;
⑦家目录:用户的家目录地址。例如root的家目录为/root,所以当root登入后就会立刻跑到/root目录下;
⑧Shell:当用户登入系统后就会取得一个Shell来与系统核心沟通,每个账户预设额定bash就由该字段指定。
真正的账号密码保存在/etc/shadow文件的字段中,不过该文件字段显示的是加密后的密码文本。一般用户如果密码忘了,使用root账号输入passwd命令重设密码即可。如果root密码忘了,可通过重启系统进入维护模式,在开机选单过程中,在linux16项目后面加入rd.break或init=/bin/bash来进入维护模式:
然后按下Ctrl+x键重启,系统就会进入到维护模式,即无须输入密码即可获得root权限。输入init=/bin/bash时系统会主动给予root权限的bash接口,此时就可用passwd命令修改密码了。
新增用户账号的命令为:$ useradd
;而给新用户账号设置密码的命令为:$ passwd
;命令$ userdel
的功能是删除用户的相关数据,而用户的数据有:
①用户账号/密码相关参数:/etc/passwd,/etc/shadow;
②使用者群组相关参数:/etc/group,/etc/gshadow;
③用户个人文件数据:/home/username,/var/spool/mail/username。
例如:
新建一个TestGroup群组的命令为:$ groupadd TestGroup
将用户userA和userB添加到群组额定命令为:
$ useradd -G TestGroup userA
$ useradd -G TestGroup userB
如果想从系统中删除用户,默认情况下userdel命令会只删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。如果加上-r参数则userdel命令会产生用户的HOME目录以及邮件目录,但系统仍可能留有已删除用户的其他文件。如果想要完整的将某个账号完整移除,最好可以在输入userdel -r username
命令之前,先使用find -user username
查出整个系统内属于username的文件,然后再进行删除。
基本上群组的内容都与两个文件有关:/etc/group,/etc/gshadow,其内容也很简单,就是上面两个文件的新增、修改与移除而已。
例如:
新建一个群组group1的命令为:
$ groupadd group1
将刚才建立的group1改为mygroup,GID为201的命令为:
$ groupmod -g 201 -n mygroup group1
删除mygroup的命令为:
$ groupdel mygroup
将一般使用者身份转换成root有两种方式:
①以su -直接将身份变成root即可,但这个命令需要root的密码;
②以sudo命令执行root的命令,这个命令需要用户自己的密码。
所以多人共管同一部主机时,sudo要比su好用,至少root密码不会泄露。
注意:并非所有人都能执行sudo,而是仅有规范到/etc/sudoers内的用户才能执行sudo命令,一开始系统默认仅有root可以执行sudo。除root之外的其他账号,如果想使用sudo执行属于root的权限命令,则root需要先使用visudo去修改/etc/sudoers:
$ visudo
>>> ....(前面省略)....
>>> root ALL=(ALL) ALL # 大约在98行左右
>>> vbird ALL=(ALL) ALL # 这一行新添加的
>>> ....(底下省略)....
如果想不需要密码可使用sudo,则可将/etc/sudoers修改为:
vbird1 All=(All) NOPASSWD:ALL
Windows系统的账户权限有3种类型:
①管理员:其具有最高的管理和使用权限,能改变系统所有设置,可以安装和删除程序,能访问计算机上所有的文件,还拥有控制其他用户的权限;
②普通用户:其是受到一定限制的账户,在系统中可以创建多个此类账户,也可以改变其账户类型。该账户可以访问已经安装在计算机上的程序,可以设置自己账户的图片、密码等,但无权更改大多数计算机设置;
③来宾用户:最低权限账户,无法对系统做任何修改,主要用于远程登录的网上用户访问计算机系统。
其通过“控制面板”→“用户账号”进行设置。
八、系统进程
一个程序被加载到内存当中运作,那么在内存内的数据就被称为进程(process)。进程是操作系统中非常重要的概念,所有系统上面跑的数据都会以进程的形态存在。在Linux系统中触发任何一个事件时,系统都会将它定义成为一个进程,并且给予这个进程一个ID称为PID,同时依据启动这个进程的用户与相关属性关系,给予这个PID一组有效的权限设定。从此以后这个PID能够在系统上面进行的动作,就与这个PID的权限有关。
Linux的进程呼叫通常称为fork-and-exec的流程,进程都会由父进程以复制(fork)的方式产生一个一模一样的子进程,然后被复制出来的子进程再以exec的方式来执行实际要进行的程序,最终就成为一个子进程的存在。
常驻在内存当中的进程通常都是负责一些系统所提供的功能,以服务用户各项任务,因此这些常驻程序被我们称为系统服务daemon。系统服务非常多,不过主要大致分成系统本身所需要的服务,例如排程服务crond、atd、rsyslogd等;以及负责网络联机的服务,例如Apache、 named、postfix、vsftpd等。网络服务有趣的地方在于,这些程序执行后会启动一个可以负责网络监听的端口port,以响应外部客户端client的联机要求。
Linux最棒的地方在于它的多人多任务环境,但CPU切换进程的工作,与这些工作进入到CPU运作的排程(CPU排程而非crontab排程) 会影响到系统的整体效能。目前Linux使用的多任务切换行为是非常棒的一个机制,几乎可以将PC的性能整个压榨出来,由于效能非常好,因此当多人同时登入系统时,并不会感受到进程切换的存在!这就是多人多任务的环境!
Linux几乎可以说是绝对不会宕机的,因为它可以在任何时候将某个被困住的进程kill掉,然后再重新执行该进程而不用重新启动。
进行系统管理的行为中,其实每个工作都是目前bash的子进程,即彼此之间是有相关性的。我们无法以job control的方式由tty1的环境去管理tty2的bash!由于假设我们只有一个终端接口,因此出现提示字符让你操作的环境就称为前台foreground,至于其他工作就可以放入后台background去暂停或运行。
注意:放入后台的工作想要继续运行的话,其必须不能与使用者互动。放入后台的工作是不可以使用Ctrl+c来终止的,但可使用bg/fg命令呼叫该工作!
通常造成僵尸进程是因为该进程应该已经执行完毕,或者是因故应该要终止了,但是该进程的父进程却无法完整的将该进程结束掉,而造成该进程一直留在内存当中。当系统不稳定的时候就容易造成所谓的僵尸进程,可能是因为程序写的不好啦,或者是使用者的操作习惯不良等所造成。如果你发现在某个进程的CMD字段后面有标记时,就代表该进程是僵尸进程,例如:
Linux给予进程一个所谓的优先执行序priority, PRI,PRI值越低代表优先级越高。不过PRI值是由内核动态调整的,用户无法直接调整PRI值。如果你想要调整进程的执行顺序时,就得要通过nice值,nice值就是下表的NI字段。
PRI与NI间的关系为:PRI(new) = PRI(old) + nice
nice值有正有负,既然PRI越小越早被执行,所以当nice值为负值时,该进程就会降低PRI值,亦即会变的优先被处理。但nice值的设置规则为:
①nice值可调整的范围为-20 ~ 19;
②root可随意调整自己或他人进程的nice值,调整范围为-20 ~ 19;
③一般使用者仅可调整自己进程的nice值,调整范围仅为0 ~ 19 (避免一般用户抢占系统资源);
④一般使用者仅可将nice值越调越高,例如本来nice为5,则未来仅能调整到大于5。
设定某个进程的nice值有两种方式:
①一开始执行程序就立即给予一个特定的nice值:用nice命令;
②调整某个已存在PID的nice值:用renice命令。
在选择调度策略时,我们可以使用不同的标准,例如,取决于系统上的典型进程组合,或者取决于应用程序中线程的要求。最常用的标准是:
①CPU利用率:理想情况下,CPU会在100%的时间内处于忙碌状态,这样我们就不会浪费任何CPU周期;
②吞吐量:单位时间内完成的进程数;
③周转时间:完成特定任务所需的经过(挂钟)时间,从出生到死亡;
④等待时间:就绪队列中的任务等待在CPU上运行所花费的时间;
⑤响应时间:从提交请求到获得响应所用的时间;
⑥平均负载:就绪队列中的平均进程数。在Linux上,它由“uptime”和“who”报告。
一般来说,我们希望优化标准的平均值,即最大化CPU利用率和吞吐量,并最小化所有其他标准。还希望最小化标准的方差,因为用户更喜欢一致可预测的系统而不是不一致的系统,即使后者平均表现更好。
实时应用程序是实时处理数据的应用程序,即没有延迟。从调度的角度来看,这意味着任务具有明确定义的时间限制。处理必须在定义的约束内完成才能被认为是正确的,特别是,没有在给定的期限内完成一个过程可能会导致不正确的功能。我们可以区分两种类型的实时系统:
①软实时系统不保证关键实时进程何时会被调度,而只保证关键进程具有更高的优先级。一个典型的例子是视频和音频流处理:错过deadline会影响播放比特的质量,但不是致命的。
②在硬实时系统中,任务必须在截止日期前得到服务,因此调度程序必须能够保证这一点。例如,飞机或其他安全关键系统的控制就是这种情况。
Linux内核支持POSIX实时规范要求的软实时调度策略SCHED_RR和SCHED_FIFO。实时进程由单独的调度程序管理,在<kernel/sched/rt.c>中定义。从内核的角度来看,实时进程与其他进程相比有一个关键的区别:如果有一个可运行的实时任务,它就会运行,除非有另一个具有更高优先级的实时任务。PREEMPT_RT补丁集是一个官方内核补丁集,它为Linux内核提供了硬实时功能。
Windows系统下的进程主要通过“任务管理器”进行操作。
九、系统服务
系统为了某些功能必须要提供一些服务(不论是系统本身还是网络方面),这个服务称为service,service的提供总需要程序运作,达成这个service的程序被称为daemon。例如完成例行性工作排程服务service的程序就是crond这个daemon。不必去专门区分daemon与service,可以将两者视为相同,因为达成某个服务是需要一支daemon在背景中运作的,没有daemon就不会有service。
一般来说,当我们以命令模式或图形模式进入Linux系统后,系统就已经提供了很多服务。服务被建立并挂到Linux使用时,通常在服务名称后加一个d,例如at与cron这两个服务的程序文件名为atd与crond,这个d代表的就是daemon的意思。
现在的Linux distribution都使用systemd启动服务管理机制,其好处有:
①平行处理所有服务,加速开机流程:旧的init启动脚本是一项一项任务依序启动的模式,因此不相依的服务也要一个个的等待。但目前我们硬件主机系统与操作系统几乎都支持多核心架构,完全可以支持服务同时启动。systemd可以让所有的服务同时启动,所以会发现系统启动的速度变快了;
②一经要求就响应的on-demand启动方式:systemd全部就仅是一支systemd服务搭配systemctl命令来处理,无需其他额外的命令来支持。此外systemd由于常驻内存,因此任何要求on-demand都可以立即处理后续的daemon启动的任务;
③服务相依性的自我检查:由于systemd可以自定义服务相依性的检查,因此如果B服务是架构在A服务上面启动的,那当你没有启动A服务的情况下仅手动启动B服务时,systemd会自动帮你启动A服务,这样可以免去管理员去一项项服务的分析;
④依daemon功能分类:systemd下面管理的服务很多,为了理清所有服务功能,首先systemd定义所有的服务为一个服务单位unit,并将该unit归类到不同的服务类型type去。旧的init仅分为stand alone与super daemon实在不够用,systemd将服务单位区分为service,socket,target,path,snapshot,timer等多种不同类型,方便管理员的分类与记忆;
⑤将多个daemon集合成为一个群组:systemd可将许多的功能集合成为一个target项目,这个项目主要在设计操作环境的配置,所以集合了许多daemon,执行某个target就是执行多个daemon的意思;
⑥向下兼容旧的init服务脚本:基本上systemd是可以兼容于init的启动脚本,因此旧的init启动脚本也能够通过systemd来管理,只是更进阶的systemd功能没有办法支持就是了。
systemd配置文件相关的目录有:
①/lib/systemd/system:每个服务最主要的启动脚本设定;
②/run/systemd/system:系统执行过程中所产生的服务脚本,其执行优先序比/lib/systemd/system高;
③/etc/systemd/system:管理员依据主机系统的需求所建立的执行脚本,其执行优先序比/run/systemd/system高。
也就是说系统开机会不会执行某些服务其实是看/etc/systemd/system底下的设定,所以该目录底下就是一大堆连接档,而实际执行的systemd启动脚本配置文件都是放置在/lib/systemd/system底下的。因此如果你想要修改某个服务启动的设定,应该要去/lib/systemd/system底下修改才对。/etc/systemd/system仅是连接到正确的执行脚本配置文件而已,想要看执行脚本设定也应该到/lib/systemd/system底下查阅。
几种比较常见的systemd服务类型有:
其中以.service系统服务类型最常见。
systemd启动服务的机制主要是通过systemctl命令来处理的。一般来说,服务启动有两个阶段:一个是开机时设定要不要启动这个服务,另一个是你现在要不要启动这个服务,这两者之间有很大的差异。
不应使用kill命令的方式来关闭一个正常的服务,否则systemctl会无法继续监控该服务。
daemon有几个常见状态:
①active(running):正有一支或多支程序在系统中执行,例如正在执行中的vsftpd;
②active(exited):仅执行一次就正常结束的服务,目前并没有任何程序在系统中执行,例如开机或挂载时才会进行一次的quotaon功能;
③active(waiting):正在执行当中,不过还在等待其他事件才能继续处理,例如打印的队列相关服务就是这种状态;
④inactive:服务目前没有运行的意思。
daemon的预设状态有:
①enabled:这个daemon将在开机时被执行;
②disabled:这个daemon在开机时不会被执行;
③static:这个daemon不可以自动启动(enable 不可),不过可能会被其他的enabled服务来唤醒(相依属性的服务);
④mask:这个daemon无论如何都无法被启动,因为已经被强制注销(非删除),可通过systemctl unmask方式改回原本状态。
例如:针对chronyd服务的操作
还可通过参数list-units和list-unit-files来查看系统上服务的存在,使用systemctl list-unit-files命令会将系统上所有的服务通通列出来,而不像list-units仅以unit分类作大致的说明:
如果不想知道那么多的unit项目,只想知道service这种类别的daemon,且不论是否已经启动通通要列出来:
跟操作界面相关性较高的target主要有以下几个:
①graphical.target:就是命令加上图形界面,这个项目已经包含了底下的multi-user.target项目;
②multi-user.target:纯命令模式;
③rescue.target:在无法使用root登入的情况下,systemd在开机时会多加一个额外的暂时系统,与原本的系统无关,这时你可以取得root的权限来维护你的系统。但这是额外系统,因此可能需要用chroot方式来取得你原有的系统;
④emergency.target:紧急处理系统的错误,还是需要使用root登入的情况,在无法使用rescue.target时,可以尝试使用这种模式;
⑤shutdown.target:就是关机的流程;
⑥getty.target:可以设定你需要几个tty之类的,如果想要降低tty的项目,可以修改这个的配置文件。
正常的模式是multi-user.target以及graphical.target两个,救援2方面的模式主要是rescue.target以及更严重的emergency.target。
通过systemctl分析各服务之间的相依性:
使用reverse参数可以查出谁会用到某个target:
跟daemon运行有关的目录有:
①/lib/systemd/system:默认的启动脚本配置文件都放在这里,所以这里的数据尽量不要修改,要修改的话就修改/etc/systemd/system;
②/run/systemd/system:系统执行过程中所产生的服务脚本,其执行优先序比/lib/systemd/system高;
③/etc/systemd/system:管理员依据主机系统的需求所建立的执行脚本,其执行优先序比/run/systemd/system高;
④/var/lib:一些会产生数据的服务都会将其数据写入到/var/lib目录中;
⑤/run:放置了很多daemon的暂存档,包括lock file以及PID file等。
Linux系统使用/etc/services将服务与端口号对应在一起:
上图中,第一栏为daemon的名称,第二栏为该daemon所使用的端口号与网络数据封包协议,封包协议分为TCP和UDP。
以sshd.service为例说明systemctl配置文件设定项目的情况:
如上图所示,可将配置文件的设定分为3个部分:
①Unit:unit本身的说明以及与其他相依daemon的设定,包括在什么服务之后才启动此unit之类的设定值;
②Service、Socket、Timer、Mount、Path:不同的unit type得使用相对应的设定项目,这个项目内主要是规范服务启动的脚本、环境配置文件档名、重新启动的方式等;
③Install:这个项目就是将此unit安装到哪个target里面的意思。
Linux服务器(不是桌面型环境)中预设启动的服务有:
Windows系统通过“电脑右键”→“管理”→“服务和应用程序”→“服务”来进入SCM服务控制管理器。其负责配置、启动、停止服务,显示所有配置服务的名称、说明、状态、启动类型和用户名称的列表:
服务的“启动”选项有:自动、手动、禁止;
服务的“登录为”选项有:
①Local System本地系统:该账户具有相当高的权限,隶属于本地Administrators用户组,所有本地Administrators用户能够进行的操作该账户也能够进行。该账户还能够控制文件的权限(NTFS文件系统)和注册表权限,甚至占据所有者权限来取得访问资格。如果机器处于域中,运行于该账户的服务还可以使用机器账户在同一个域中其他机器的自动认证。运行于该账户下的进程能够使用空会话(null session)去访问网络资源,而且其他一些Windows用户模式下的核心组件也运行于该账户下,例如system32/Smss.exe等。但它不能够访问其他账户的配置。
②Network Service网络服务:其是预设的拥有本机部分权限的本地账户,能够以计算机的名义访问网络资源。但是它没有Local System那么多的权限,以该账户运行的服务会根据实际环境把访问凭据提交给远程计算机。该账户通常可以访问Network Service、Everyone组,还有认证用户有权限访问的资源。
③Local Service本地服务:其是预设的拥有最小权限的本地账户,并在网络凭证中具有匿名的身份。该账户下的进程和运行于Network Service账户下的进程的区别在于Local Service账户下的进程只能访问允许匿名访问的网络资源。
十、工作排程
Linux系统可帮你提醒任务,例如每天早上8:00要服务器连接上音响,这样的例行性排程,以及某天12:00发一封邮件提醒重大事件,这样的突发性排程。Linux排程主要是通过crontab与at系统服务来实现的:
①at:其可以处理仅执行一次就结束排程的指令,必须要有atd服务的支持;
②crontab:其所设定的工作会循环执行下去,可循环时间为分钟、小时、每周等,其必须要有crond服务的支持。
$ systemctl restart atd # 重新启动atd服务
$ systemctl enable atd # 让这个服务开机就自动启动
$ systemctl status atd # 查阅atd目前的状态
因为安全原因,并不是所有账户都可以进行at工作排程。我们可以利用/etc/at.allow与/etc/at.deny这两个文件来进行at的使用限制,加上这两个文件后,at的工作情况其实是这样的:①先找寻/etc/at.allow这个文件,写在这个文件中的使用者才能使用at,没有在这个文件中的使用者则不能使用at (即使没有写在at.deny当中);
②如果/etc/at.allow不存在,就寻找/etc/at.deny这个文件,若写在这个at.deny的使用者则不能使用at,而没有在这个at.deny文件中的使用者,就可以使用at;
③如果两个文件都不存在,那么只有root可以使用at这个指令。
单一工作排程的进行使用at这个指令,将at加上一个时间即可!基本的语法如下:
如果下达了错误的排程,可使用atq查询,atrm来删除:
crontab排程也可以人工施加限制:
①/etc/cron.allow:将可以使用crontab的账号写入其中,若不在这个文件内的使用者则不可使用crontab;
②/etc/cron.deny:将不可以使用crontab的账号写入其中,若未记录到这个文件当中的使用者,就可以使用crontab。
当用户使用crontab指令建立工作排程之后,该项工作就会被记录到/var/spool/cron/里面,而且是以账号来作为判别的。例如dmtsai使用crontab后,它的工作会被记录到/var/spool/cron/dmtsai里面。注意:不要使用vi直接编辑该文件,因为可能由于输入语法错误会导致无法执行cron。
例如:用dmtsai身份在每天12:00发信给自己
$ crontab -e
# 此时会进入vi的编辑界面让你编辑 注意每项工作都是一行
>>> 0 12 * * * mail -s “at 12:00” dmtsai < /home/dmtsai/.bashrc
# 分 时 日 月 周 |<==============指令串==============>|
查询使用者目前的crontab内容:
不论是at还是crontab,其最小时间单位是分钟,基本上它们的工作是每分钟检查一次来处理的,就是整分(秒为0的时候)!
anacron并不是用来取代crontab的,而是处理非24小时一直启动的Linux系统的crontab的执行,以及因为某些原因导致的超时而没有被执行的排程工作。其实anacron也是每个小时被crond执行一次,然后anacron再去检测相关的排程任务有没有被执行,如果有超时的工作存在就执行该排程任务,执行完毕或无须执行任何排程时anacron就停止了。由于anacron预设会以一天、七天、一个月为期去侦测系统未进行的crontab任务,因此对于某些特殊的使用环境非常有帮助。
利用systemd.timer也可以定期执行服务,其相比于crond的优势有:
①由于所有的systemd服务产生的信息都会被记录log,因此其比crond在debug上面更清楚方便;
②各项timer的工作可以跟systemd的服务相结合;
③各项timer的工作可以跟control group(cgroup,用来取代/etc/secure/limit.conf的功能)结合,来限制该工作的资源利用;
④其最小时间单位可到秒甚至毫秒。
其劣势有:
①没有email通知功能;
②没有类似anacron的一段时间内的随机取样功能random_delay。
想要使用systemd的timer功能必须满足以下条件:
①系统的timer.target一定要启动;
②要有一个sname.service的服务存在(sname是你自定义的名称);
③要有一个sname.timer的时间启动服务存在。
例如:使用systemd.timer来实现:开机后2小时开始执行一次backup.service,自动第一次执行后,未来每两天要执行一次backup.service:
Windows系统通过“任务计划程序”来进行工作排程,其通过“电脑右键”→“管理”→“系统工具”→“任务计划程序”来进入。通过该程序即可实现at和crontab的功能。
十一、登录文件
当Linux系统出现不明原因的问题时,通过查阅登录文件就可能知道系统出了什么问题。详细而确实的分析以及备份系统的登录文件是一个系统管理员应该进行的任务。登录文件就是记录系统活动信息的几个文件,例如何时、何地(来源IP)、何人(什么服务名称)、做了什么动作(登录信息),就是记录系统在什么时候由哪个程序做了什么样的行为,发生了何种事件等。
登录文件的重要性主要体现在以下方面:
①解决系统方面的错误:由于系统会将硬件侦测过程记录在登录文件内,只要通过查询登录文件就能够了解系统做了什么事情;
②解决网络服务的问题:由于网络服务的各种问题通常都会被写入特别的登录文件,只要查询登录文件就会知道出了什么差错,例如如果无法启动邮件服务器postfix,查询/var/log/maillog通常就可以得到答案;
③过往事件记录:这个东西相当重要,例如你发现WWW服务(httpd软件)在某个时刻流量特别大,可以通过登录文件去找出该时段是哪些IP在联机,查询的网页数据为何,就能够知道原因。如果你的系统被入侵,登录文件会记录登录者IP,其可协助进行来源追查。
登录文件的权限通常设定为仅有root能够读取,常见的登录文件有以下几个:
①/var/log/boot.log:开机时系统内核会侦测与启动硬件,并启动内核支持的功能,这些流程会记录在/var/log/boot.log里。不过这个文件只会保存这次开机启动的信息,前次开机的信息并不会被保留;
②/var/log/dmesg:记录系统在开机时内核侦测过程所产生的各项信息。由于系统默认将开机时内核的硬件侦测过程取消显示,因此额外将数据记录在这个文件中;
③/var/log/lastlog:记录系统上面所有账号最近一次登入系统时的相关信息;
④/var/log/maillog或/var/log/mail/:记录邮件的往来信息,其实主要是记录postfix(SMTP协议提供者)与dovecot(POP3协议提供者)所产生的信息;
⑤/var/log/messages:这个文件相当重要,几乎系统发生的错误信息(或者是重要信息)都会记录在这个文件中。如果系统发生莫名的错误时,这个文件是一定要查阅的登录文件之一;(未在Jetson Xavier NX上看到该文件)
⑥/var/log/secure:基本上只要涉及需要输入账号密码的软件,其登入时(不管登入正确与否)都会被记录在这个文件中。包括系统的login程序、图形接口登入所使用的gdm程序、su和sudo程序,网络联机的ssh和telnet程序等,登入信息都会被记录到这里;(未在Jetson Xavier NX上看到该文件)
⑦/var/log/wtmp,/var/log/faillog:这两个文件可以记录正确登入系统者的账户信息wtmp与错误登入时所使用的账户信息faillog,这对于追踪一般账号的使用行为很有帮助;
⑧/var/log/httpd/,/var/log/samba/:不同的网络服务会使用它们自己的登录文件来记载它们自己产生的各项信息,上述目录内则是个别服务所制订的登录文件;
其他Ubuntu系统中的登录文件有:
①/var/log/alternatives.log:记录更新替代信息;
②/var/log/apport.log:记录应用程序崩溃信息;
③/var/log/apt:记录用apt安装卸载软件的信息;
④/var/log/auth.log:记录用户认证日志信息;
⑤/var/log/btmp:记录所有失败登录的信息,需要用last命令查看;
⑥/var/log/dist-upgrade:记录用dist-upgrade更新软件的信息;
⑦/var/log/dpkg.log:记录安装或dpkg命令清除软件包的信息;
⑧/var/log/fontconfig.log:记录与字体配置有关的信息;
⑨/var/log/installer:记录软件安装的日志信息;
⑩/var/log/kern.log:记录内核产生的信息,有助于在定制内核出问题时解决问题;
⑪/var/log/lastlog:记录系统上面所有账号最近一次登入系统时的相关信息;
⑫/var/log/lightdm:记录桌面窗口管理器LightDM相关的信息;
⑬/var/log/syslog:事件记录监控程序日志;
⑭/var/log/tallylog:其是个二进制日志,记录认证失败的信息,与PAM认证登录有关;
⑮/var/log/wtmp:记录正确登入系统者的账户信息;
⑯/var/log/Xorg.x.log:记录来自x的日志信息。
Linux系统提供rsyslog.service服务来统一管理登录文件。不过如果任凭登录文件持续记录的话,由于系统产生的信息天天都有,那么你的登录文件的容量会越来越大。如果登录文件容量太大时,可能导致大文件读写效率不佳(因为要从磁盘读入内存,越大的文件消耗内存越多)。可以通过logrotate(登录文件轮替)来自动化处理登录文件容量与更新的问题。logrotate基本上就是将旧的登录文件更改名称然后建立一个空的登录文件,如此一来新的登录文件将重新开始记录。只要将旧的登录文件保留一小段时间,如果旧的记录保存一段时间(大概保存几个月)没有问题,就可以让系统自动将其删除,免得占用宝贵的硬盘空间。
针对登录文件所需的功能,我们需要的服务与程序有:
①systemd-journald.service:最主要的信息接收者,由systemd提供;
②rsyslog.service:主要记录登录系统与网络等服务的信息;
③logrotate:主要进行登录文件的轮替功能。
一般系统产生的信息经过记录下来的数据中,每条信息均会记录以下几个重要数据:
①事件发生的日期与时间;
②发生此事件的主机名;
③启动此事件的服务名称(如systemd,crond等)或指令与函数名称(如su,login等);
④该信息的实际数据内容。
rsyslogd针对各种服务与信息记录的情况可在配置文件/etc/rsyslog.conf中进行设置,其规定了:
①什么服务;
②什么等级的信息;
③需要被记录到哪里(哪个文件)。
关于服务名称Linux内核的syslog可识别以下类型:
Linux内核的syslog将信息等级分为8级:
需要注意在信息等级前的[.=!]链接符号,其意思为:
①.:代表比后面还严重的等价(含该等级)都被记录下来;
②.=:代表所需要的等级就是后面写的等级,其他的都不要;
③.!:代表不等于,即除了该等级外的其他等级都要记录。
如果你需要特殊文件来辅助记录时,可以通过/etc/rsyslog.conf进行设置,这样就可以重复的将许多信息记录在不同的文件当中,以方便进行管理。例如:
例如:想要将新闻资料news和例行工作排程cron的信息都写入到/var/log/cronnews文件中。但这两个程序的警告信息额外记录到/var/log/cronnews.warn文件中,可如下设定/etc/rsyslog.conf:
news.*;cron.* /var/log/cronnews
news.=warn;cron.=warn /var/log/cronnews.warn
注意:news与cron的警告信息也会写入/var/log/cronnews文件中。
关于登录文件的轮替,rsyslogd是利用daemon方式来启动的,当有需要时立刻就会执行,但logrotate却是在规定的时间到了之后才进行登录文件的轮替,所以logrotate是挂在cron下面的。logrotate程序的参数配置文件是:
①/etc/logrotate.conf,其是主要的参数文件;
②/etc/logrotate.d/,其是一个目录,目录下的所有文件都会被主动读入到/etc/logrotate.conf当中进行。在/etc/logrotate.d/里面的文件中如果没有规定一些细节设定,则以/etc/logrotate.conf文件的规定作为默认值。
logrotate的执行过程如下图所示:
自定义登录文件的轮替功能示例:
假设你已经建立了/var/log/admin.log这个文件,需设定以下相关信息:
①登录文件轮替一个月进行一次;
②该登录文件若大于10MB时,则主动进行轮替,不需要考虑一个月的期限;
③保存5个备份文件;
④备份文件需要压缩。
由于systemd是内核唤醒的,又是第一支执行的软件,它可以主动呼叫systemd-journald来协助记载登录文件,因此在开机过程中的所有信息,包括启动服务与服务启动失败的情况等,都可以直接记录到systemd-journald中。不过systemd-journald使用内存记录登录文件,因此重新启动后开机前的登录文件信息就不会被记载了。也就是说,systemd-journald用来管理与查询这次开机后的登录信息,而rsyslogd可以用来记录以前及现在的所有数据到磁盘文件中,方便未来进行查询。
可使用journalctl来查看登录信息:
如果想要将你的数据存储到登录文件中,可以使用logger程序传输信息:
使用logger的示例:
Windows系统通过“事件查看器”来管理系统日志,其通过“电脑右键”→“管理”→“系统工具”→“事件查看器”来进入。
Win10的系统日志随时都在记录着电脑的状态,当系统出现一些异常或者错误提示时,我们可以通过查看系统日志来分析出错原因。进入“事件查看器”,选择“Windows日志”→“系统”→“将所有事件另存为”,保存系统日志,然后打开这个文件就可以了。
每当出现一些未捕获异常时,Win10系统都会将异常信息写入到Windows事件日志中。
如果想将自己在Windows系统下运行程序的信息写入Windows事件日志中,可如下操作:
①创建Message DLL:“VS2017”→“新建”→“项目”→“Windows桌面向导”,项目名称“MyMessages”,然后如下图设置选项:
在项目源文件中新建添加文件“MyMessages.mc”,如下图所示:
“MyMessages.mc”文件的内容使用微软官方给出的示例代码:
; // ***** Sample.mc *****
; // This is the header section.
MessageIdTypedef=DWORD
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR
)
FacilityNames=(System=0x0:FACILITY_SYSTEM
Runtime=0x2:FACILITY_RUNTIME
Stubs=0x3:FACILITY_STUBS
Io=0x4:FACILITY_IO_ERROR_CODE
)
LanguageNames=(English=0x409:MSG00409)
; // The following are message definitions.
MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=MSG_BAD_COMMAND
Language=English
You have chosen an incorrect command.
.
MessageId=0x2
Severity=Warning
Facility=Io
SymbolicName=MSG_BAD_PARM1
Language=English
Cannot reconnect to the server.
.
MessageId=0x3
Severity=Success
Facility=System
SymbolicName=MSG_STRIKE_ANY_KEY
Language=English
Press any key to continue . . . %0
.
MessageId=0x4
Severity=Error
Facility=System
SymbolicName=MSG_CMD_DELETE
Language=English
File %1 contains %2 which is in error.
.
MessageId=0x5
Severity=Informational
Facility=System
SymbolicName=MSG_RETRYS
Language=English
There have been %1!d! attempts with %2!d!%% success%! Disconnect from
the server and try again later.
.
配置项目属性:
生成解决方案,会在项目文件夹下生成:MyMessages.h 和 MyMessages.rc 两个文件。将这两个文件添加到项目中并“重新生成解决方案”,即可产生我们需要的MyMessages.dll文件。
②在注册表中注册该MyMessages.dll文件:在如下图所示的目录下新建项,命名为MyApp,再在MyApp下创建两个子项,并如图设置属性值,其中EventMessageFile的值为dll文件的路径:
③创建控制台程序,调用dll写消息到Windows应用程序日志:
#include <iostream>
#include "windows.h"
#include "MyMessages.h" // 拷贝到Client项目中
void ReportOneEvent(LPCTSTR szMsg) {
HANDLE h = RegisterEventSource(NULL, TEXT("MyApp"));
if (h == NULL)
printf("register source error");
if (!ReportEvent(h,
EVENTLOG_ERROR_TYPE,
6,
MSG_BAD_COMMAND, //so the event description is "error three"
NULL,
1,
wcslen(szMsg),
&szMsg, //this szMsg("event test") is the event data
(void*)szMsg))
printf("event report error");
DeregisterEventSource(h);
}
int main(int argc, char* argv[]) {
ReportOneEvent(TEXT("Event Logging Test!"));
return 0;
}
运行该程序后,打开Windows事件日志,即可以看到已将消息写如到日志中:
十二、数据备份
事实上系统有可能由于未预料到的伤害而导致系统发生错误,这些伤害包括硬件损坏,软件问题,人为操作不当,网络攻击等。数据备份是系统损毁时进行恢复的重要手段。具有备份意义的文件通常可分为两大类:
①系统基本设定信息,包括:
<1> /etc/整个目录;
<2> /home/整个目录;
<3> /var/spool/mail/
<4> /var/spoll/{at|cron}/
<5> /boot/
<6> /root/
<7> 如果自行安装过其他软件,/usr/local/和/opt最好也备份一下。
②类似网络服务的内容数据,包括:
<1>软件本身的配置文件,例如/etc/整个目录,/usr/local/整个目录;
<2>软件服务提供的数据,以WWW及Mariadb为例,/var/www整个目录或/srv/www整个目录,以及系统的用户家目录,/var/lib/mysql整个目录;
<3>其他在Linux主机上提供服务的数据库文件。
如果由于磁盘空间有限,无法完全备份上述所有数据时,至少要备份以下目录:
① /etc
② /home
③ /root
④ /var/spool/mail/,/var/spool/cron/,/var/spool/at/
⑤ /var/lib/
关于备份用存储介质,在经费充足的情况下,建议使用外接式NAS设备。备份方式优先选择累积备份,指的是在系统在进行完第一次完整备份后,经过一段时间的运作,比较系统与备份文件之间的差异,仅备份有差异的文件而已。而第二次累积备份则与第一次累积备份的数据比较,也是仅备份有差异的数据而已。因此备份的数据量小且快速!备份也很有效率。备份频率建议:普通数据一般每周一次,数据库数据每日一次即可。备份工具主要有xfsdump,以及快速工具rsync:
备份是非常重要的工作,需要自己编写shell script配合crontab去自动化执行。
十三、函数链接库
Linux系统中依据函数链接库被使用的类型而分为两大类,分别是静态(Static)与动态(Dynamic)链接库两类:静态库的名称为lib*.a,动态库的名称为lib*.so。目前的Linux distribution比较倾向于使用动态链接库,因为动态库的升级更方便!
如果我们将常用到的动态链接库先加载到二级缓存中,当软件要取用动态链接库时就不需要从硬盘里面读出,可以增进动态链接库的读取速度。可通过ldconfig与/etc/ld.so.conf来实现:
①在/etc/ld.so.conf里面写下想要读入缓存当中的动态链接库所在的目录,注意是目录而不是文件;
②利用ldconfig程序将/etc/ld.so.conf的资料读入缓存中;
③将数据记录一份在/etc/ld.so.cache文件中。
例如:想要将系统下的mariadb链接库加载到缓存当中时可以这样做:
利用ldd指令可判断某个可执行的binary文件需调用哪些动态链接库。例如想要知道/usr/bin/passwd这个程序调用的动态链接库有哪些时可以这样做:
Windows系统下也有动态链接库和静态链接库,基本都与Linux下的情况相同,只是Windows的动态链接库是.dll文件,静态链接库是.lib文件。
总结
以上就是关于Linux和Windows操作系统基础功能要讲的内容,欢迎大家对本文章进行补充和指正。
参考资料
《鸟哥的Linux私房菜 基础学习篇》,人民邮电出版社出版
《Make:Linux for Makers》,Maker Media
《Operating Systems Foundations with Linux on the Raspberry Pi》,Arm Education Media
https://zhuanlan.zhihu/p/483888207
https://blog.csdn/chanrenyuan/article/details/41458697
https://blog.csdn/qq_37077262/article/details/103979429
https://blog.csdn/sduqzx/article/details/48351385
版权声明:本文标题:服务器开发系列(三)——Linux与Windows操作系统基础功能对比 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1725920372h892902.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论