(48)LINUX应用编程和网络编程之三Linux获取系统信息

3.3.1.关于时间的概念
3.3.1.一、GMT时间
(1)GMT是格林尼治时间,也就是格林尼治地区的当地之间。
(2)GMT时间的意义?【用格林尼治的当地时间做为全球国际时间】,用以描述全球性的事件的时间,方便你们记忆
(3)通常为了方便,一个国家都统一使用一个当地时间。
 
3.3.1.二、UTC时间
(1)GMT时间是之前使用的,使用天文来测试的,近些年来愈来愈多的使用UTC原子钟时间。
(2)关于北京时间,能够参考:http://www.cnblogs.com/qiuyi21/archive/2008/03/04/1089456.html
 
3.3.1.三、计算机中与时间有关的部件
(1)点时间和段时间。段时间=点时间-点时间
(2)定时器和实时时钟。定时器(timer)定的时间就是段时间,实时时钟(RTC)就是和点时间有关的一个器件。
 
3.3.2.linux系统中的时间
3.3.2.一、jiffies的引入
(1)jiffies是linux内核中的一个全局变量,这个变量用来记录以【内核的节拍时间】为单位时间长度的一个数值。
(2)内核配置的时候定义了一个节拍时间,实际上linux内核的调度系统工做时就是以这个节拍时间为时间片的。
(3)jiffies变量开机时有一个基准值,而后内核每过一个节拍时间jiffies就会加1,而后到了系统的任意一个时间咱们当前时间就被jiffies这个变量所标注。
 
3.3.2.二、linux系统如何记录时间
(1)内核在开机启动的时候会读取RTC硬件获取一个时间做为初始基准时间,这个基准时间对应一个jiffies值(这个基准时间换算成jiffies值的方法是:用这个时间减去1970-01-01 00:00:00 +0000(UTC),而后把这个时间段换算成jiffies数值),这个jiffies值做为咱们开机时的基准jiffies值存在。而后系统运行时每一个时钟节拍的末尾都会给jiffies这个全局变量加1,所以操做系统就使用jiffies这个全局变量记录了下来当前的时间。当咱们须要当前时间点时,就用jiffies这个时间点去计算(计算方法就是先把这个jiffies值对应的时间段算出来,而后加上1970-01-01 00:00:00 +0000(UTC)便可获得这个时间点)
(2)其实操做系统只在开机时读一次RTC,整个系统运行过程当中RTC是无做用的。RTC的真正做用实际上是在OS的2次开机之间进行时间的保存。
(3)理解时必定要点时间和段时间结合起来理解。jiffies这个变量记录的实际上是段时间(其实就是当前时间和1970-01-01 00:00:00 +0000(UTC)这个时间的差值)
(4)一个时间节拍的时间取决于操做系统的配置,现代linux系统通常是10ms或者1ms。这个时间其实就是调度时间,在内核中用HZ来记录和表示。若是HZ定义成1000难么时钟节拍就是1/HZ,也就是1ms。这些在学习驱动时会用到。
 
3.3.2.三、linux中时间相关的系统调用
(1)经常使用的时间相关的API和C库函数有9个:time/ctime/localtime/gmtime/mktime/asctime/strftime/gettimeofday/settimeofday有9个:time/ctime/localtime/gmtime/mktime/asctime/strftime/gettimeofday/settimeofday
(2)time系统调用返回当前时间以秒为单位的距离1970-01-01 00:00:00 +0000(UTC)过去的秒数。这个time内部就是用jiffies换算获得的秒数。其余函数基本都是围绕着time来工做的。
(3)gmtime和localtime会把time获得的秒数变成一个struct tm结构体表示的时间。区别是gmtime获得的是国际时间,而localtime获得的是本地(指的是你运行localtime函数的程序所在的计算机所设置的时区对应的本地时间)时间。mktime用来完成相反方向的转换(struct tm到time_t)
(4)若是从struct tm出发想获得字符串格式的时间,能够用asctime或者strftime均可以。(若是从time_t出发想获得字符串格式的时间用ctime便可)
(5)gettimeofday返回的时间是由struct timeval和struct timezone这两个结构体来共同表示的,其中timeval表示时间,而timezone表示时区。settimeofday是用来设置当前的时间和时区的。
(6)总结:无论用哪一个系统调用,最终获得的时间本质上都是一个时间(这个时间最终都是从kernel中记录的jiffies中计算得来的),只不过不一样的函数返回的时间的格式不一样,精度不一样。
 
 
3.3.3.时间相关API实战1
3.3.3.一、time
(1)time能获得一个当前时间距离标准起点时间1970-01-01 00:00:00 +0000(UTC)过去了多少秒
 
3.3.3.二、ctime
(1)ctime能够从time_t出发获得一个容易观察的字符串格式的当前时间。
(2)ctime好处是很简单好用,能够直接获得当前时间的字符串格式,直接打印来看。坏处是ctime的打印时间格式是固定的,无法按照咱们的想法去变。
(3)实验结果能够看出ctime函数获得的时间是考虑了计算机中的本地时间的(计算机中的时区设置)
 
3.3.3.三、gmtime和localtime
(1)gmtime获取的时间中:年份是以1970为基准的差值,月份是0表示1月,小时数是以UTC时间的0时区为标准的小时数(北京是东8区,所以北京时间比这个时间大8)
(2)猜想localtime和gmtime的惟一区别就是localtime以当前计算机中设置的时区为小时的时间基准,其他同样。实践证实咱们的猜想是正确的。
 
 
3.3.4.时间相关API实战2
3.3.4.一、mktime
(1)从OS中读取时间时用不到mktime的,这个mktime是用来向操做系统设置时间时用的。
3.3.4.二、asctime
(1)asctime获得一个固定格式的字符串格式的当前时间,效果上和ctime同样的。区别是ctime从time_t出发,而asctime从struct tm出发。
 
3.3.4.三、strftime
(1)asctime和ctime获得的时间字符串都是固定格式的,无法用户自定义格式
(2)若是须要用户自定义时间的格式,则须要用strftime。
 
3.3.4.四、gettimeofday和settimeofday
(1)前面讲到的基于time函数的那个系列都是以秒为单位来获取时间的,没有比秒更精确的时间。
(2)有时候咱们程序但愿获得很是精确的时间(譬如以us为单位),这时候就只能经过gettimeofday来实现了。
 
 
3.3.5.linux中使用随机数
3.3.5.一、随机数和伪随机数
(1)随机数是随机出现,没有任何规律的一组数列。
(2)真正的彻底随机的数列是不存在的,只是一种理想状况。咱们平时要用到随机数时通常只能经过一些算法获得一个伪随机数序列。
(3)咱们平时说到随机数,基本都指的是伪随机数。
 
3.3.5.二、linux中随机数相关API
(1)连续屡次调用rand函数能够返回一个伪随机数序列
#include <stdlib.h>
int rand(void);
(2)srand函数用来设置rand获取的伪随机序列的种子
 
 
 
3.3.5.三、实战演示
(1)单纯使用rand重复调用n次,就会获得一个0-RAND_MAX之间的伪随机数,若是须要调整范围,能够获得随机数序列后再进行计算。
(2)单纯使用rand来获得伪随机数序列有缺陷,每次执行程序获得的伪随机序列是同一个序列,无法获得其余序列
(3)缘由是由于rand内部的算法实际上是经过一个种子(seed,其实就是一个原始参数,int类型),rand内部默认是使用1做为seed的,种子必定的算法也是必定的,那么每次获得的伪随机序列确定是同一个。
(4)因此要想每次执行这个程序获取的伪随机序列不一样,则每次都要给不一样的种子。用srand函数来设置种子。
 
3.3.5.四、总结和说明
(1)在每次执行程序时,先用srand设置一个不一样的种子,而后再屡次调用rand获取一个伪随机序列,这样就能够每次都获得一个不一样的伪随机序列。
(2)通常常规作法是用time函数的返回值来作srand的参数。
 
3.3.5.五、在linux系统中获取真正的随机数
(1)linux系统收集系统中的一些随机发生的事件的时间(譬若有人动鼠标,譬如触摸屏的操做和坐标等)做为随机种子去生成随机数序列。
代码示例:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
  int i = 0, val = 0;
  if (argc != 2)
    {
        printf("usage: %s num\n", argv[0]);
        return -1;
    }
    printf("RAND_MAX = %d.\n", RAND_MAX);        // 2147483647
    srand(atoi(argv[1]));                               //经过外界传递初始化种子
    //srand((unsigned)time(NULL));               //经过srand来给rand函数以不断变化的种子
    for (i=0; i<20 ;i++)                                  //设定产生随机数的个数
    {
        val = rand();
        printf("%d ", (val % 10000));               //生成0到1000之间的随机数
    }
    printf("\n");
    return 0;
}   
 
 
3.3.6.proc文件系统介绍
3.3.6.一、操做系统级别的调试
(1)简单程序单步调试
(2)复杂程序printf打印信息调试
(3)框架体系日志记录信息调试
(4)内核调试的困境
3.3.6.二、proc虚拟文件系统的工做原理
(1)linux内核是一个很是庞大、很是复杂的一个单独的程序,对于这样的一个程序来讲调试是很是复杂的。
(2)像kernel这样庞大的项目,给里面添加/更改一个功能是很是麻烦的,由于你这添加的一个功能可能会影响其余已经有的。
(3)早期内核版本中尽管调试很麻烦,可是高手们还能够凭借我的超凡脱俗的能力去驾驭。可是到了2.4左右的版本的时候,这个难度已经很是大了。
(4)为了下降内核调试和学习的难度,内核开发者们在内核中添加了一些属性专门用于调试内核,proc文件系统就是一个尝试。
(5)proc文件系统的思路是:在内核中构建一个虚拟文件系统/proc,内核运行时将内核中一些关键的数据结构以文件的方式呈如今/proc目录中的一些特定文件中,这样至关于将不可见的内核中的数据结构以可视化的方式呈现给内核的开发者。
(6)proc文件系统给了开发者一种调试内核的方法:咱们经过实时的观察/proc/xxx文件,来观看内核中特定数据结构的值。在咱们添加一个新功能的先后来对比,就能够知道这个新功能产生的影响对仍是不对。
(7)proc目录下的文件大小都是0,由于这些文件自己并不存在于硬盘中,他也不是一个真实文件,他只是一个接口,当咱们去读取这个文件时,其实内核并非去硬盘上找这个文件,而是映射为内核内部一个数据结构被读取而且格式化成字符串返回给咱们。因此尽管咱们看到的仍是一个文件内容字符串,和普通文件同样的;可是实际上咱们知道这个内容是实时的从内核中数据结构来的,而不是硬盘中来的。
 
3.3.6.三、经常使用proc中的文件介绍
(1)/proc/cmdline
(2)/proc/cpuinfo
(3)/proc/devices
(4)/proc/interrupts
 
 
3.3.7.proc文件系统的使用
3.3.7.一、cat以手工查看
3.3.7.二、程序中能够文件IO访问
3.3.7.三、在shell程序中用cat命令结合正则表达式来获取并处理内核信息
3.3.7.三、扩展:sys文件系统
(1)sys文件系统本质上和proc文件系统是同样的,都是虚拟文件系统,都在根目录下有个目录(一个是/proc目录,另外一个是/sys目录),所以都不是硬盘中的文件,【都是内核中的数据结构的可视化接口。】
(2)不一样的是/proc中的文件只能读,可是/sys中的文件能够读写。读/sys中的文件就是获取内核中数据结构的值,而写入/sys中的文件就是设置内核中的数据结构的元素的值。
(3)历史上刚开始先有/proc文件系统,人们但愿经过这种技术来调试内核。实际作出来后确实颇有用,因此不少内核开发者都去内核调价代码向/proc目录中写文件,并且刚开始的时候内核管理者对proc目录的使用也没有什么经验也没什么统一规划,后来的结果就是proc里面的东西又多又杂乱。
(4)后来以为proc中的内容太多太乱缺少统一规划,因而乎又添加了sys目录。sys文件系统一开始就作了很好的规划和约定,因此后来使用sys目录时有了规矩。
 
补充:
sysfs是用来向用户空间导出内核对象的一种文件系统,经过它,用户空间程序能够查看、甚至修改内核数据结构。该文件系统是基于内核数据结构kobject创建起来的,同时该文件系统的目录结构反映了相关内核数据结构的层次结构。因为kobject是组成设备模型的基本结构,所以sysfs也包括了系统中设备的信息,它提供了系统硬件的拓扑信息。
因为sysfs提供了访问、修改内核数据结构的一种手段,于是内核模块也能够经过该文件系统向用户空间导出接口用于访问、修改模块的参数。
在引入sysfs后,内核向用户处处接口的方式有/proc文件系统,sysfs文件系统,ioctl命令。
虽然sysfs的信息来自于kobject,可是kobject和sysfs的关联不是自动创建的,必须经过kobject_add才能把一个kobject添加到sysfs中。
因为内核中使用kobject的主要部件是硬件相关的部分,于是sysfs包含的最主要的内容就是硬件相关的内容,包括总线、设备、驱动程序等。Sysfs挂载点为/sys
相关文章
相关标签/搜索