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

3.3.1.关于时间的概念

3.3.1.1、GMT时间

(1)GMT是格林尼治时间,也就是格林尼治地区的当地之间。

(2)GMT时间的意义?【用格林尼治的当地时间作为全球国际时间】,用以描述全球性的事件的时间,方便大家记忆

(3)一般为了方便,一个国家都统一使用一个当地时间。

3.3.1.2、UTC时间

(1)GMT时间是以前使用的,使用天文来测试的,近些年来越来越多的使用UTC原子钟时间。

(2)关于北京时间,可以参考:http://www.cnblogs.com/qiuyi21/archive/2008/03/04/1089456.html

3.3.1.3、计算机中与时间有关的部件

(1)点时间和段时间。段时间=点时间-点时间

(2)定时器和实时时钟。定时器(timer)定的时间就是段时间,实时时钟(RTC)就是和点时间有关的一个器件。

3.3.2.linux系统中的时间

3.3.2.1、jiffies的引入

(1)jiffies是linux内核中的一个全局变量,这个变量用来记录以【内核的节拍时间】为单位时间长度的一个数值。

(2)内核配置的时候定义了一个节拍时间,实际上linux内核的调度系统工作时就是以这个节拍时间为时间片的。

(3)jiffies变量开机时有一个基准值,然后内核每过一个节拍时间jiffies就会加1,然后到了系统的任意一个时间我们当前时间就被jiffies这个变量所标注。

3.3.2.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.3、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.1、time

(1)time能得到一个当前时间距离标准起点时间1970-01-01 00:00:00 +0000(UTC)过去了多少秒

3.3.3.2、ctime

(1)ctime可以从time_t出发得到一个容易观察的字符串格式的当前时间。

(2)ctime好处是很简单好用,可以直接得到当前时间的字符串格式,直接打印来看。坏处是ctime的打印时间格式是固定的,没法按照我们的想法去变。

(3)实验结果可以看出ctime函数得到的时间是考虑了计算机中的本地时间的(计算机中的时区设置)

3.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.1、mktime

(1)从OS中读取时间时用不到mktime的,这个mktime是用来向操作系统设置时间时用的。

3.3.4.2、asctime

(1)asctime得到一个固定格式的字符串格式的当前时间,效果上和ctime一样的。区别是ctime从time_t出发,而asctime从struct tm出发。

3.3.4.3、strftime

(1)asctime和ctime得到的时间字符串都是固定格式的,没法用户自定义格式

(2)如果需要用户自定义时间的格式,则需要用strftime。

3.3.4.4、gettimeofday和settimeofday

(1)前面讲到的基于time函数的那个系列都是以秒为单位来获取时间的,没有比秒更精确的时间。

(2)有时候我们程序希望得到非常精确的时间(譬如以us为单位),这时候就只能通过gettimeofday来实现了。

3.3.5.linux中使用随机数

3.3.5.1、随机数和伪随机数

(1)随机数是随机出现,没有任何规律的一组数列。

(2)真正的完全随机的数列是不存在的,只是一种理想情况。我们平时要用到随机数时一般只能通过一些算法得到一个伪随机数序列。

(3)我们平时说到随机数,基本都指的是伪随机数。

3.3.5.2、linux中随机数相关API

(1)连续多次调用rand函数可以返回一个伪随机数序列

#include <stdlib.h>

int rand(void);

(2)srand函数用来设置rand获取的伪随机序列的种子

3.3.5.3、实战演示

(1)单纯使用rand重复调用n次,就会得到一个0-RAND_MAX之间的伪随机数,如果需要调整范围,可以得到随机数序列后再进行计算。

(2)单纯使用rand来得到伪随机数序列有缺陷,每次执行程序得到的伪随机序列是同一个序列,没法得到其他序列

(3)原因是因为rand内部的算法其实是通过一个种子(seed,其实就是一个原始参数,int类型),rand内部默认是使用1作为seed的,种子一定的算法也是一定的,那么每次得到的伪随机序列肯定是同一个。

(4)所以要想每次执行这个程序获取的伪随机序列不同,则每次都要给不同的种子。用srand函数来设置种子。

3.3.5.4、总结和说明

(1)在每次执行程序时,先用srand设置一个不同的种子,然后再多次调用rand获取一个伪随机序列,这样就可以每次都得到一个不同的伪随机序列。

(2)一般常规做法是用time函数的返回值来做srand的参数。

3.3.5.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、操作系统级别的调试

(1)简单程序单步调试

(2)复杂程序printf打印信息调试

(3)框架体系日志记录信息调试

(4)内核调试的困境

3.3.6.2、proc虚拟文件系统的工作原理

(1)linux内核是一个非常庞大、非常复杂的一个单独的程序,对于这样的一个程序来说调试是非常复杂的。

(2)像kernel这样庞大的项目,给里面添加/更改一个功能是非常麻烦的,因为你这添加的一个功能可能会影响其他已经有的。

(3)早期内核版本中尽管调试很麻烦,但是高手们还可以凭借个人超凡脱俗的能力去驾驭。但是到了2.4左右的版本的时候,这个难度已经非常大了。

(4)为了降低内核调试和学习的难度,内核开发者们在内核中添加了一些属性专门用于调试内核,proc文件系统就是一个尝试。

(5)proc文件系统的思路是:在内核中构建一个虚拟文件系统/proc,内核运行时将内核中一些关键的数据结构以文件的方式呈现在/proc目录中的一些特定文件中,这样相当于将不可见的内核中的数据结构以可视化的方式呈现给内核的开发者。

(6)proc文件系统给了开发者一种调试内核的方法:我们通过实时的观察/proc/xxx文件,来观看内核中特定数据结构的值。在我们添加一个新功能的前后来对比,就可以知道这个新功能产生的影响对还是不对。

(7)proc目录下的文件大小都是0,因为这些文件本身并不存在于硬盘中,他也不是一个真实文件,他只是一个接口,当我们去读取这个文件时,其实内核并不是去硬盘上找这个文件,而是映射为内核内部一个数据结构被读取并且格式化成字符串返回给我们。所以尽管我们看到的还是一个文件内容字符串,和普通文件一样的;但是实际上我们知道这个内容是实时的从内核中数据结构来的,而不是硬盘中来的。

3.3.6.3、常用proc中的文件介绍

(1)/proc/cmdline

(2)/proc/cpuinfo

(3)/proc/devices

(4)/proc/interrupts

3.3.7.proc文件系统的使用

3.3.7.1、cat以手工查看

3.3.7.2、程序中可以文件IO访问

3.3.7.3、在shell程序中用cat命令结合正则表达式来获取并处理内核信息

3.3.7.3、扩展: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

时间: 2024-08-23 01:56:34

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

(50)LINUX应用编程和网络编程之五 Linux信号(进程间通信)

信号实现进程间的通信 3.5.1.什么是信号 3.5.1.1.信号是内容受限(只是一个int型的数字)的一种异步通信机制 (1)信号的目的:用来通信(进程与进程之间的通信) (2)信号是异步的(对比硬件中断),信号好像就是一种软件中断. (3)信号本质上是int型数字编号(事先定义好的) 3.5.1.2.信号由谁发出 (1)用户在终端按下按键 (2)硬件异常后由操作系统内核发出信号 (3)用户使用kill命令向其他进程发出信号 (4)某种软件条件满足后也会发出信号,如alarm闹钟时间到会产生S

Linux程序设计学习笔记----网络编程之网络数据包拆封包与字节顺序大小端

网络数据包的封包与拆包 过程如下: 将数据从一台计算机通过一定的路径发送到另一台计算机.应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装(Encapsulation),如下图所示: 不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据包(packet),在链路层叫做帧(frame).数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理. 上图对应两台计算机在同一网段中的情况,

(46)LINUX应用编程和网络编程之一Linux应用编程框架

3.1.1.应用编程框架介绍 3.1.1.1.什么是应用编程 (1)整个嵌入式linux核心课程包括5个点,按照学习顺序依次是:裸机.C高级.uboot和系统移植.linux应用编程和网络编程.驱动. (2)典型的嵌入式产品就是基于嵌入式linux操作系统来工作的.典型的嵌入式产品的研发过程就是:第一步让linux系统在硬件上跑起来(系统移植工作),第二步基于linux系统来开发应用程序实现产品功能. (3)基于linux去做应用编程,其实就是通过调用linux的[系统API]来实现应用需要完成

XMPP-05Socket编程之网络编程篇

要学习XMPP,就要先了解Socket编程,在学习Socket之前,还要先了解一下网络编程 一.网络编程基本概念 通过使用套接字来达到进程间通信目的的编程就是网络编程. 网络编程从大的方面说就是对信息的发送到接收,中间传输为物理线路的作用,编程人员可以不用考虑…… 网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的!中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理

66.JAVA编程思想——网络编程

66.JAVA编程思想--网络编程 历史上的网络编程都倾向于困难.复杂,而且极易出错. 程序员必须掌握与网络有关的大量细节,有时甚至要对硬件有深刻的认识.一般地,我们需要理解连网协议中不同的"层"(Layer).而且对于每个连网库,一般都包含了数量众多的函数,分别涉及信息块的连接.打包和拆包:这些块的来回运输:以及握手等等.这是一项令人痛苦的工作.但是,连网本身的概念并不是很难.我们想获得位于其他地方某台机器上的信息,并把它们移到这儿:或者相反.这与读写文件非常相似,只是文件存在于远程

iOS网络编程开发—网络编程基础

iOS网络编程开发—网络编程基础 一.网络编程 1.简单说明 在移动互联网时代,移动应用的特征有: (1)几乎所有应用都需要用到网络,比如QQ.微博.网易新闻.优酷.百度地图 (2)只有通过网络跟外界进行数据交互.数据更新,应用才能保持新鲜.活力 (3)如果没有了网络,也就缺少了数据变化,无论外观多么华丽,终将变成一潭死水 移动网络应用 = 良好的UI + 良好的用户体验 + 实时更新的数据 新闻:网易新闻.新浪新闻.搜狐新闻.腾讯新闻 视频:优酷.百度视频.搜狐视频.爱奇艺视频 音乐:QQ音乐

linux服务端的网络编程

常见的Linux服务端的开发模型有多进程.多线程和IO复用,即select.poll和epoll三种方式,其中现在广泛使用的IO模型主要epoll,关于该模型的性能相较于select和poll要好不少,本文也主要讨论该模型而忽略另外两种IO复用模型. 多线程相较于多进程开销比较小,但是要主要主线程往子线程传递数据的时候要注意变量互斥访问来保证线程安全. epoll模型在Linux2.6内核中引入的,改进了select中的一些明显设计上的缺点,具有更高的效率.主要体现在以下几个方面: 1. epo

Linux下的socket网络编程

linux 网络编程是通过socket(套接字)接口实现,Socket是一种文件描述符,socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开-读/写-关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件. socket 类型 常见的socket有3种类型如下.     (1)流式socket(SOCK_STREAM )     流式套接字提供可靠

linux下简单socket网络编程

在进行socket网络编程时, 我们需要了解一些必备的知识,例如什么是socket,ipv4的地址结构,套接字类型等等,不然上来直接看代码就会晕,当初学习网络编程时,看书上的例子,总有感觉书上讲的都很简要.再或者讲的原理太多把人绕晕.我这里只想让大家简单知道怎么使用socket进行网络编程并且给出的例子可以直接使用参考. 1. 什么是socket (1) socket 可以看成是用户进程与网络协议栈的编程接口.就是说应用层可以看成是用户进程,传输层网络层数据链路层看成网络协议栈,因为这三个层的传

第8章 面向对象高级编程与网络编程

面向对象的特征 一.多态 程序在运行的过程中,根据传递的参数的不同,执行不同的函数或者操作不同的代码,这种在运行过程中才确定调用的方式成为运行时多态 import abc #多态:同一种事物的多种形态 class Animal: #同一类事物:动物 def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def ta