3.3获取系统信息
时间的概念:
GMT时间与UTC时间
GMT(格林尼治时间),描述全球性事件的时间
UTC(世界同一时间(现常用)) UTC + 时区差 = 本地时间 (时区差东为正,西为负)
例:北京(东八区):0800 UTC + 0800 = 北京时间
计算机中与时间有关的部件
点时间与段时间
段时间 = 点时间 - 点时间
定时器(timer)与实时时钟
定时器定的时间为段时间,实时时钟(RTC)就是和点时间有关的一个器件。
linux系统中的时间
jiffies的引入
jiffies是linux内核中的一个全局变量,这个变量用来记录以内核的节拍时间为单位时间长度的一个数值。
内核配置的时候定义了一个节拍时间,linux内核的调度系统工作时就是以这个节拍时间为时间片的
jiffies变量开机的时候存在一个基准值,内核每过一个节拍时间jiffiees就会+1,到系统的任意一个时间我们当前时间就被jiffies这个变量所标注。
((当前jiffies - 开机时候的jiffies )* 节拍= 当前时间距离开机的时间。)
linux系统如何记录时间
内核在开机启动的时候会读取RTC,获取一个时间作为基准时间,对应一个jiffies值(这个基准时间换算成jiffies值的方法:这个时间 - 1970-01-01 00:00:00 +0000 (UTC) ,将得到的时间段换算成jiffies值,这个值作为基础值)。系统时每个jiffies(每个时钟节拍)的末尾都会给jiffies+1。
当前时间点:jiffies对应的时间段 + 1970-01-01 00:00:00 +0000 (UTC)
操作系统只在开机时读一次RTC,运行过程中RTC无用。RTC的真正作用是在OS的两次开机之间进行时间的保存。
jiffies记录的是段时间(当前时间与 - 1970-01-01 00:00:00 +0000 (UTC) )
一个时间节拍取决于OS的配置,现代linux一般是10ms或者1ms。这个时间就是调度时间,在内核中用HZ来记录和表示。节拍 = 1/HZ
linux中时间相关的系统调用
time/ctime/localtime/gmtime/mktime/asctime/strftime/gettimeofday/settimeofday
time系统调用用返回以秒为单位的距离 1970-01-01 00:00:00 +0000 (UTC) 过去的秒数。time内部用jiffies换算来的
其他函数基本都是围绕time来工作的。
gmtime(得到国际时间)与 localtime(得到本地时间)会把time得到的秒数变成一个 struct tm 结构体表示的时间
mktime 用来完成相反方向的转换(struct tm 到 time_t)
struct_tm 出发得到字符串格式的时间:asctime 与 strftime都可以 (如果从time_t出发想得到字符串格式的时间用 ctime )
gettimeofday 返回的 有 struct timeval 与 struct timezone 表示,timeval表示时间,timezone表示时区
时间相关API实战
time
得到一个距离1970-01-01 00:00:00 +0000多少秒的时间
time_t tNow = -1;
//tNow = time(NULL);//返回值
time(&tNow);//指针
if(tNow < 0)
{
perror("time");
return -1;
}
printf("time :%ld年.\n",tNow/60/60/24/365);
ctime
从time_t出发得到一个容易观察的字符串格式的当前时间,可以得到当前时间的字符串格式
但是打印的格式是固定的没法重定义格式。
//返回一个字符串
printf("ctime: %s",ctime(&tNow));
gmtime与localtime
得到 struct tm
gmttime
获取的时间是以1900为基准的差值,月份表示(0-11),小时是以UTC时间0时区来表示,北京时间+8
time_t tNow = -1;
struct tm tmNow;memset(&tmNow, 0, sizeof(tmNow));
gmtime_r(&tNow, &tmNow);
printf("gmtime: %d年%d月%d日.\n",tmNow.tm_year+1900, tmNow.tm_mon+1, tmNow.tm_mday);
localtime
获取的时间是以1900为基准的差值,月份表示(0-11),小时是以OS设定的时间为准。
mktime
从OS读取时间用不到mktime,是用来想OS设置时间。
asctime
与 ctime 格式完全一致。区别是ctime 是从 time_t 出发,asctime是从 struct tm 出发
memset(&tmNow, 0, sizeof(tmNow));
localtime_r(&tNow, &tmNow);
printf("localtime: %d年%d月%d日%d时.\n",tmNow.tm_year, tmNow.tm_mon, tmNow.tm_mday, tmNow.tm_hour);
printf("asctime: %s.\n",asctime(&tmNow));
strftime
用户自定义格式。
char buf[100]={0};
memset(&tmNow, 0, sizeof(tmNow));
localtime_r(&tNow, &tmNow);
printf("localtime: %d年%d月%d日%d时.\n",tmNow.tm_year, tmNow.tm_mon, tmNow.tm_mday, tmNow.tm_hour);
memset(buf,0,sizeof(buf));
strftime(buf, sizeof(buf), "%F,%H-%M-%S",&tmNow);
printf("[%s]\n",buf);
gettimeofday与settimeofday
微秒级别的精度。
struct timeval tv = {0};
struct timezone tz = {0};
int ret = -1;
//memset(&tv,0,sizeof(tv));
ret = gettimeofday(&tv,&tz);
if(ret < 0)
{
perror("gettimeofday");
return -1;
}
printf("seconds: %ld\n",tv.tv_sec);
linux中使用随机数
随机数是随机出现,没有任何规律的一组数列。平时用的随机数一般知识通过一些算法得到的伪随机数。
linux中随机数相关API
多次调用rand函数
srand设置rand获取伪随机序列的种子
实战演练
单纯使用rand重复调用n次,得到0-RAND_MAX之间的伪随机数。
但是每次得到的随机序列是相同的,解决方案:换种子。使用srand来换种子
一般用time函数的返回值来做srand的参数(确保种子不会重复)
int main(int argc, char **argv)
{
if(argc!=2)
{
printf("usage: %s num\n",argv[0]);
}
int val = 0;
srand(time(NULL));//设定种子
for(int i =0;i<6;i++)
{
val = rand();
printf("%d ",val%6);
}
printf("\n");return 0;
}
在linux中获得真正的随机数
linux系统收集系统中随机发生的事件的时间(鼠标移动,操作触摸屏及其坐标等)作为随机种子来生成随机数序列。
proc文件系统
操作系统级别的调式
简单程序单步调试
复杂程序printf打印信息调试
框架体系日志记录信息调试
内核调式的困境
proc虚拟文件系统的工作原理
linux内核是一个非常庞大、非常复杂的一个单独的程序,对其调试非常复杂。
像kernel这样庞大的项目,给里面添加/更改一个功能是非常麻烦的,因为你添加的功能可能会影响其他有的功能。
为了降低内核调试和学习的难度,内核开发者在内核中添加了一些属性专门来调试内核——proc文件系统。
proc文件系统的思路: 在内核中构建一个虚拟文件系统/proc,内核运行时将内核中的一些关键的数据结构以文件的方式呈现在/proc目录中的一些特定文件中,这样相当于将不可见的内核中数据结构以可视化的方式呈现给内核开发者。
proc文件系统给了开发者一种调试内核的方法:通过实时观察/proc/xxx文件,来查看内核中特定数据结构的值。在添加一个新功能后对值进行前后对比,知道其影响是否正确。
proc目录下的文件大小都是0,因为这些文件本身并不存在与硬盘中,他不是一个真实文件,只是一个接口。读取文件时,内核不是去硬盘上找文件,而是映射为内核内部一个数据结构被读取且格式化成字符串返回。尽管我们看到的还是一个文件内容字符串,和普通文件一样,但是实际上这个内容是实时从内核中数据结构来的,不是硬盘中来的。
常用proc中的文件介绍
/proc/cmdline
/proc/cpuinfo
/proc/devices
/proc/interrupts
proc文件系统的使用
cat手工查看
cat /proc/version
程序中可以文件IO访问
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int fd = -1;
char buf[512] = {0};
if(argc != 2)
{
printf("usage : %s -v|-d\n",argv[0]);//命令行./a.out -v/-d
return -1;
}
if(!strcmp(argv[1],"-v"))
{
fd = open("/proc/version",O_RDONLY);
if(fd < 0)
{
perror("open /proc/version");
return -1;
}
read(fd, buf, sizeof(buf));
printf("结果是:%s\n",buf);
}else if(!strcmp(argv[1],"-d"))
{
fd = open("/proc/devices",O_RDONLY);if(fd < 0)
{
perror("open /proc/devices");
return -1;
}
read(fd, buf, sizeof(buf));
printf("结果是:%s\n",buf);
}
return 0;
}
在sehll程序中用cat命令结合正则表达式来获取并处理内核信息
扩展:sys文件系统
sys文件系统本质上与proc文件系统一样的,都是虚拟文件系统,都在根目录下(/proc与/sys)。都不是硬盘中的文件,都是内核中的数据结构的可视化接口。
不同的是/proc中的文件只能读,/sys中的文件可以读写。读/sys中的文件就是获取内核中数据结构的值,写入/sys中的文件就是设置内核中的数据结构元素的值。