嵌入式 Linux系统编程(六)——系统信息

一、时间

    Linux系统下常用的时间类型:time_tstruct tmstruct timevalstruct timespec

1、time_t类型时间

        time_t实际是一个长整型。其值表示为从UTC(coordinated universal time)时间1970年1月1日00时00分00秒(也称为Linux系统的Epoch时间)到当前时刻的秒数。由于time_t类型长度的限制,它所表示的时间不能晚于2038年1月19日03时14分07秒(UTC)。

    #include <time.h>

 

time_t time(time_t *t);

成功返回从1970年1月1日0时0分0秒开始到当前时间的秒数,失败返回-1,设置errno。如果t不是NULL,则返回值也可以存储在t指向的空间中。

typedef  long  time_t; 

因此,time(time_t *t)返回的是一个long int类型。

#include <time.h>

 

char *asctime(const struct tm *tm);

char *asctime_r(const struct tm *tm, char *buf);

char *ctime(const time_t *timep);

char *ctime_r(const time_t *timep, char *buf);

struct tm *gmtime(const time_t *timep);

struct tm *gmtime_r(const time_t *timep, struct tm *result);

struct tm *localtime(const time_t *timep);

struct tm *localtime_r(const time_t *timep, struct tm *result);

time_t mktime(struct tm *tm);

    使用time()函数获取当前时间的time_t值,使用ctime()函数将time_t转为当地时间字符串。ctime( )将参数timep指向的time_t时间信息转换成实际所使用的时间日期表示方法,并以字符串形式返回。字符串格式为:"Wed Feb 20 21:23:00 2016\n"。

 2、struct tm类型时间

struct tm {

               int tm_sec;         /* seconds */

               int tm_min;         /* minutes */

               int tm_hour;        /* hours */

               int tm_mday;        /* day of the month */

               int tm_mon;         /* month */0-11

               int tm_year;        /* year */1900

               int tm_wday;        /* day of the week */

               int tm_yday;        /* day in the year */

               int tm_isdst;       /* daylight saving time */

           };

    ANSI C标准称使用tm结构的这种时间表示为分解时间(broken-down time)。
    使用gmtime( )和localtime( )可将time_t时间类型转换为tm结构体,gmtime返回时间为UTC时间,localtime返回时间为本地时间。
    使用mktime( )将tm结构体转换为time_t时间类型;
    使用asctime( )将struct tm转换为字符串形式。

#include <time.h>

 

size_t strftime(char *s, size_t max, const char *format,const struct tm *tm);

3struct timeval类型时间

struct timeval {

               time_t      tv_sec;     /* seconds */

               suseconds_t tv_usec;    /* microseconds */

           };

#include <sys/time.h>

 

int gettimeofday(struct timeval *tv, struct timezone *tz);

 

int settimeofday(const struct timeval *tv, const struct timezone *tz);

 

4、struct timespec类型时间

struct timespec{  

time_t  tv_sec    Seconds;

long    tv_nsec   Nanoseconds;}; 


 5、程序实例

#include <time.h>

#include <string.h>

#include <stdio.h>

int main(int argc, char **argv)

{

    struct tm *t;

    time_t timep;

    char buf[64] = {0};

    timep = time(NULL);

    t = localtime(&timep);

    sprintf(buf, "%d-%d-%d %d:%d:%d\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);

    printf(buf);

    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S\n", t);

    printf(buf);

    return 0;

}

二、随机数

    获取伪随机数的函数:

#include <stdlib.h>

 

int rand(void);

int rand_r(unsigned int *seedp);

void srand(unsigned int seed);

    Linux系统一般通过使用系统时间作为种子获取伪随机数,只要每次使用相同的seed值,就能得到相同的伪随机数列。

struct timeval tmseed;

gettimeofday(&tmseed, NULL);

srand(tmseed.tv_usec);

int i = rand();

 

    产生一定范围随机数的通用表示公式:
  要取得[a,b)的随机整数,使用(rand() % (b-a))+ a;
  要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a,另一种表示为a + (int)b * rand() / (RAND_MAX + 1);
  要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1;
  通用公式:a + rand() % n;其中的a是起始值,n是整数的范围;
  要取得0~1之间的浮点数,可以使用rand() / double(RAND_MAX)。

 

获取真随机数:

        Linux内核实现了一个随机数产生器,从理论上说这个随机数产生器产生的是真随机数。为了获得真正意义上的随机数,需要一个外部的噪声源。Linux内核找到了一个完美的噪声源产生者--就是使用计算机的人。我们在使用计算机时敲击键盘的时间间隔,移动鼠标的距离与间隔,特定中断的时间间隔等等,这些对于计算机来讲都是属于非确定的和不可预测的。内核根据这些非确定性的设备事件维护着一个熵池,池中的数据是完全随机的。当有新的设备事件到来,内核会估计新加入的数据的随机性,当我们从熵池中取出数据时,内核会减少熵的估计值。

    有两种方法可以从熵池中获取内核随机数。一种是通过内核导出的随机数接口,另一种是通过特殊的设备文件/dev/random/dev/urandom

通过特殊设备获取内核随机数:

    如果内核熵池的估计值为0时,/dev/random将被阻塞,而/dev/urandom不会有这个限制。

    用dd命令从/dev/urandom中获取指定字节数的随机值并写入文件中保存--如果你需要以文件的形式提供随机数的话。

dd if=/dev/urandom of = file count = 1 bs = bytes

程序代码:

int get_random_number(void)

{

    static int dev_random_fd = -1;

    unsigned int random_value;

    if(-1 == dev_random_fd)

    {   

        dev_random_fd = open("/dev/random", O_RDONLY);

    }   

    char *random_byte = (char *)&random_value;

    unsigned int read_bytes = sizeof(random_value);

    do  

    {   

        int i = read(dev_random_fd, random_byte, read_bytes);

        read_bytes -= i;

        random_value += i;

    }while(read_bytes > 0);

    return random_value;

}

 

 

三、proc文件系统

        Linux系统上的/proc目录是一种文件系统,即proc文件系统是一种虚拟文件系统,存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。

        /proc 由内核控制,没有承载/proc的设备。因为/proc主要存放由内核控制的状态信息,所以大部分这些信息的逻辑位置位于内核控制的内存。
proc文件系统可以被用于收集有用的关于系统和运行中的内核的信息。
常见的重要的文件:

/proc/cpuinfo - CPU 的信息 (型号, 家族, 缓存大小等)

/proc/meminfo - 物理内存、交换空间等的信息

/proc/mounts - 已加载的文件系统的列表

/proc/devices - 可用设备的列表

/proc/filesystems - 被支持的文件系统

/proc/modules - 已加载的模块

/proc/version - 内核版本

/proc/cmdline - 系统启动时输入的内核命令行参数

/proc/interrupts- 每个IRQ相关的中断号列表

/proc/apm- 高级电源管理(APM)版本信息及电池相关状态信息,通常由apm命令使用

/proc/crypto - 系统上已安装的内核使用的密码算法及每个算法的详细信息列表

/proc/dma -每个正在使用且注册的ISA DMA通道的信息列表

/proc/ioports - 当前正在使用且已经注册过的与物理设备进行通讯的输入-输出端口范围信息列表

/proc/kallsyms 模块管理工具用来动态链接或绑定可装载模块的符号定义,由内核输出

/proc/kmsg 用来保存由内核输出的信息,通常由/sbin/klogd/bin/dmsg等程序使用

/proc/mdstat 保存RAID相关的多块磁盘的当前状态信息

 

进程目录文件介绍:

/proc目录中包含许多以数字命名的子目录,这些数字表示系统当前正在运行进程的进程号,里面包含对应进程相关的多个信息文件。

cmdline — 启动当前进程的完整命令,但僵尸进程目录中的此文件不包含任何信息;

environ — 当前进程的环境变量列表,彼此间用空字符(NULL)隔开;变量用大写字母表示,其值用小写字母表示;

exe — 指向启动当前进程的可执行文件(完整路径)的符号链接,通过/proc/N/exe可以启动当前进程的一个拷贝;

fd — 这是个目录,包含当前进程打开的每一个文件的文件描述符(file descriptor),这些文件描述符是指向实际文件的一个符号链接;

limits — 当前进程所使用的每一个受限资源的软限制、硬限制和管理单元;此文件仅可由实际启动当前进程的UID用户读取;(2.6.24以后的内核版本支持此功能);

maps — 当前进程关联到的每个可执行文件和库文件在内存中的映射区域及其访问权限所组成的列表;

mem — 当前进程所占用的内存空间,由openreadlseek等系统调用使用,不能被用户读取;

root — 指向当前进程运行根目录的符号链接;在UnixLinux系统上,通常采用chroot命令使每个进程运行于独立的根目录;

stat — 当前进程的状态信息,包含一系统格式化后的数据列,可读性差,通常由ps命令使用;

statm — 当前进程占用内存的状态信息,通常以页面page)表示;

status — stat所提供信息类似,但可读性较好,如下所示,每行表示一个属性信息

task — 目录文件,包含由当前进程所运行的每一个线程的相关信息,每个线程的相关信息文件均保存在一个由线程号(tid)命名的目录中,这类似于其内容类似于每个进程目录中的内容

 

参考博文:

Linux内核中获取真随机数(博客园 红字)