当前课程知识点:基于Linux的C++ > 第十二讲 Linux系统编程基础 > 12.9 设备 > LinuxCPP1209
接下来一节设备
设备就是包括几个主题
一个是设备类型、设备号、设备项、设备目录
一个是设备类型、设备号、设备项、设备目录
还有硬件设备和一些特殊的设备
然后我们会简单地介绍怎么控制和访问设备
然后我们会简单地介绍怎么控制和访问设备
设备也是文件
我们前面不讲过了嘛
在 Linux 操作系统下边
凡物皆文件啊
设备本身也是文件
但是这个设备文件
它不是普通的磁盘文件
这是同学们一定要注意的
读写设备的数据
需要和相应的那个设备驱动打交道的
你不跟它通信
这个数据是读写不了的
所以这个地方是和普通文件的最主要的差别
所以这个地方是和普通文件的最主要的差别
设备文件分成了两大类型
一个是字符设备 一个是块设备
所谓字符设备
它是一个读写串型数据流的像这样的一个设备
它是一个读写串型数据流的像这样的一个设备
它当然都是一个数据字节流
不管那个字节流
它到底是真正 ASCII 码字符
或者 UNICODE 码字符
还是一个整数分解成了一个字符接着一个字符方式传递的那个模式
还是一个整数分解成了一个字符接着一个字符方式传递的那个模式
还是一个整数分解成了一个字符接着一个字符方式传递的那个模式
反正它是一个字符设备 字节流
像串口 像我们终端
它实际上都是字节流
所以都是字符设备
还有一种就是块设备
它提供一种随机地读写固定尺寸的这样一个数据块
它提供一种随机地读写固定尺寸的这样一个数据块
一般来讲 你比方讲磁盘设备
它实际上可以一个扇区、一个扇区地读
那不就是一个块吗
一个扇区一个区块
我就按这个方式去读 叫块设备
平时我们一般不用它
操作系统内部用它
瞬间一次性地读取 就是这个意思
磁盘一旦挂载到我们的文件系统以后
磁盘一旦挂载到我们的文件系统以后
我们就可以使用文件或目录的方式进行操作了
我们就可以使用文件或目录的方式进行操作了
这样的时候你看上去就像和设备无关了
这样的时候你看上去就像和设备无关了
但其实依然是有固定的设备的
你想硬盘、优盘、光盘
它们的文件系统
它们的设备驱动的模式
肯定是不一样嘛
但是挂到了我们文件系统以后
你看到的有差别吗 没差别了吧
这就叫统一的一致的方式处理
同时对用户来讲是透明的
我们的程序一般是不使用块设备的
内核实现文件系统的时候才需要
使用到我们的块设备来操作文件
inux 系统的设备有大设备号和小设备号
两种标记的方式
所谓的大设备号是指定设备
所对应的哪一个设备驱动器
这个对应的关系是由内核来决定的
我们决定不了
小设备号对应的就是设备驱动器控制的单个设备
小设备号对应的就是设备驱动器控制的单个设备
或者那个设备的某一个组件
你比如讲3号设备 它是主设备
它对应于 IDE 控制器
那 IDE 控制器
也可以控制很多个单个设备呢
可以连接很多个
你比如说磁盘也行啊 磁带也行啊
CD/DVD-ROM 驱动器也行啊 对吧
那么小设备呢 后面跟着呢
大设备号、小设备号
就按照这个方式来标定它们的
主设备的小设备号从 0 开始
从设备的小设备号就是从 64 开始
每个特定的设备项就跟文件类似
每个特定的设备项就跟文件类似
可以用 mv、rm 像这样的一种命令
移动、删除 一旦挂接上去以后
它这个设备项名字就跟普通的文件一样了
它这个设备项名字就跟普通的文件一样了
如果你这样的一个设备支持读写的
那么 cp 命令本身就可以
向这个设备里边写入数据
或者从那个设备里边
把这个数据读出来
有一个 mknod() 系统调用
它可以用来创建我们的设备项
它带着三个参数
一个是 pathname 一个是 mode 一个是 dev
pathname 就是那个设备项的包含路径的名字
pathname 就是那个设备项的包含路径的名字
mode 就是那个设备的使用权限和结点类型
mode 就是那个设备的使用权限和结点类型
dev 对应的就是那个设备
注意 你用 mknod() 这个系统调用创建一个设备项
注意 你用 mknod() 这个系统调用创建一个设备项
只是表示完成与这个设备通讯的一个门户性的设置
只是表示完成与这个设备通讯的一个门户性的设置
在文件系统里边创建这个设备项
并不意味着这个设备立即就是可用的
这个地方是需要特别注意的
还有 只有超级用户才能去处理这个设备的问题
还有 只有超级用户才能去处理这个设备的问题
普通用户是没有权力管理整个操作系统内部的硬件设备的
普通用户是没有权力管理整个操作系统内部的硬件设备的
这一点也是需要注意的
所有的设备目录
已知的一般都放在 “/dev” 这个目录下边
你比如讲如果你有一块硬盘
它的设备名字叫 hda
然后它里面有一个分区 hda1
那么你一列 “/dev/hda /dev/hda1”
你能够看到这两个设备
一个是硬盘 一个是硬盘的第一个分区
这几张表格列出了 Linux 操作系统中的常见的硬件设备
这几张表格列出了 Linux 操作系统中的常见的硬件设备
有对应设备的描述和设备的名称
然后它们对应的大设备号和小设备号
具体有哪些设备 我们就不解释了
因为不同的操作系统是不一样的
你看到的信息也是不一样的
因为有的硬件设备
在某些操作系统中是有的
某些是没有的
接下来就是特殊设备
有三个最重要的特殊设备
一个是 “/dev/null”
它表示一个哑设备
我们往往称它为哑终端
任何写入哑设备的数据都会被抛弃
你想从哑设备里边读东西
那么你事实上读不到任何东西
没有任何数据可以读出来的
这就是哑设备
然后有一个 “/dev/zero”
它是一个零设备
它的行为就像文件一样
但是它的长度是无限的 内容全是 0
很容易地就从它里边读到一堆 0 出来
这就叫做零设备
还有一个满设备 “/dev/full”
它的行为同样类似于文件
但是没有任何一点空闲的空间
能够朝里边写数据
对满设备的任何一个写入总是失效的
这是三个特殊的设备
这三个特殊设备里边
最常用的特殊设备就是我们的哑设备
我们的哑终端
有的时候我们重定向的时候
就需要使用到它
我们后边有例子
还有一类特殊的设备是什么
随机数设备 有两个
一个是 “/dev/random”
一个是 “/dev/urandom”
它们负责用来生成随机数
我们前面不讲过了吗
在 C 语言里实际上就提供了一个
随机数生成函数 rand()
它用来替我们生成一个随机数
但是 C 语言 rand() 这个函数生的成随机数
它是个伪随机数 它是个假的
不是真正的随机数
C++ 没有专门的随机数生成函数
它就直接使用 C 的随机数生成函数来生成伪随机数
它就直接使用 C 的随机数生成函数来生成伪随机数
这样的一个随机数因为在某些情况下边
它是有规律可寻的
那么在一个严格的程序里边
这样的随机数显然没法用
那我们怎么才能够生成真正的随机数呢
这就要求我们生成的这个随机数序列
它是不可预测的
什么东西不可预测呢
人的行为不可预测
所以它就是完全随机的
所以 Linux 操作系统
就实现一个非常巧妙的随机数设备
它就是利用什么呢
就利用你的行为
操作系统内核会测量
用户在输入活动的过程中
它的那个时间的间隔
你比如讲 你的键盘输入
你比如讲 你的鼠标操作
两个相邻的键盘输入
和两个相邻的鼠标操作
它的时间的间隔 别人是不知道的
你自己其实也不知道
所以它是个完全无法预计的一个行为
时间间隔到底有多大
它是完全无法预计的
那么操作系统就记录这个
然后用它作为随机数
这个方式非常非常巧妙
就能够替我们生成真正的随机数
这两个随机数设备有一点差别
“/dev/random” 这个随机数设备
在没有用户输入操作的时候
它会阻塞读取随机数的那个进程
就说我没有数据给你
那么你的进程就不能做 你必须等
真正的数据来 你才能去处理
那么这个设备呢 “/dev/urandom”
就不是这样
当没有真正随机数的时候
它就直接生成伪随机数传给你
这样的话 你就不用等用户去输入
用户不输入 你就得不到用户两次输入的时间间隔了嘛
用户不输入 你就得不到用户两次输入的时间间隔了嘛
对吧 就这个意思
“/dev/random” 当在用户没有输入的时候
它就会阻塞你的读取进程
“/dev/urandom” 呢
在用户没有输入的时候
它就会成生一个伪随机数传给你
就这个模式
这是两个随机数设备
正常情况下在我们程序中都可以使用
对于设备的访问和控制
就像普通的文件一样
你比如讲 当我们想向并口设备
发送一个数据的时候
我们就调用 open() 这个函数
打开这个设备 “/dev/lp0”
0 号并口
O_WRONLY 只写模式
打开这个并口 得到它的文件描述符
是不是就像文件操作一样
跟这个地方传文件名有什么差别吗
没差别
打开它 然后 write()
向这个文件描述符里边写数据
over 写完了 close() 关闭
设备的写入就这个模式
非常非常地方便
可以使用 ioctl()
这个函数来控制硬件设备
对它进行精确的管理
对于这个函数来讲呢
它有两个参数 第一个参数
传的是指定的那个文件描述符
你想控制的是哪一个设备
这是第一个
第二个参数 你想让它做什么事
那就对应于控制那个设备要控制的命令
你比如讲 我想打开一个 CD-ROM
那我就让这个 CD-ROM 把那个仓门弹出来
OK 那你就执行这个程序
把那个 CD-ROM 那个设备的名字
作为它的参数传进去
放在 argv[1] 里
然后我们就 open 这个 argv[1] 这个设备 打开它
然后我们就 open 这个 argv[1] 这个设备 打开它
得到它的文件描述符
我们调用 ioctl()
传这个文件描述符 传它的命令
那个命令名字叫做 CDROMEJECT
弹出 CD-ROM 就是打开它的仓门
就是这个命令
它会把这个命令发给 CD-ROM 对应的那个设备
它会把这个命令发给 CD-ROM 对应的那个设备
就通过 fd 发给它了
发给它以后 那个仓门就会弹出来
就这个模式 用完了
操作完了 你就 close()
关闭这个文件描述符就完了
所以你看 整个 Linux 操作系统中
控制设备的这个模式 ioctl() 和 fctrl() 控制那个文件的方式
控制设备的这个模式 ioctl() 和 fctrl() 控制那个文件的方式
是非常非常类似的
基本上是同样的格式
能让你在进行系统编程的时候
以一致的方案来操作操作系统中的文件和设备
以一致的方案来操作操作系统中的文件和设备
-1.1 提纲
-1.2 程序设计的基本概念
-1.3 简单C/C++程序介绍
-1.4 程序设计的基本流程
-1.5 基本语法元素
-1.6 程序设计风格
-1.7 编程实践
-第一讲 C/C++基本语法元素--编程实践提交入口
-2.1 提纲
-2.2 结构化程序设计基础
-2.3 布尔数据
-2.4 分支结构
-2.5 break语句
-2.6 循环结构
-2.7 编程实践
-第二讲 程序控制结构--编程实践提交入口
-3.1 提纲
-3.2 函数声明、调用与定义
-3.3 函数调用栈框架
-3.4 编程实践
-第三讲 函数--编程实践提交入口
-4.1 提纲
-4.2 算法概念与特征
-4.3 算法描述
-4.4 算法设计与实现
-4.5 递归算法(一)
-4.6 递归算法(二)
-4.7 容错与计算复杂度
-4.8 编程实践
-第四讲 算法--编程实践提交入口
-5.1 提纲
-5.2 库与接口
-5.3 随机数库(一)
-5.4 随机数库(二)
-5.5 作用域与生存期
-5.6 典型软件开发流程(一)
-5.7 典型软件开发流程(二)
-5.8 编程实践
-第五讲 程序组织与开发方法--编程实践提交入口
-6.1 提纲
-6.2 字符
-6.3 数组(一)
-6.4 数组(二)
-6.5 结构体
-6.6 编程实践
-第六讲 复合数据类型--编程实践提交入口
-7.1 提纲
-7.2 指针基本概念
-7.3 指针与函数
-7.4 指针与复合数据类型(一)
-7.5 指针与复合数据类型(二)
-7.6 字符串
-7.7 动态存储管理(一)
-7.8 动态存储管理(二)
-7.9 引用
-7.10 编程实践
-第七讲 指针与引用--编程实践提交入口
-8.1 提纲
-8.2 数据抽象(一)
-8.3 数据抽象(二)
-8.4 链表(一)
-8.5 链表(二)
-8.6 链表(三)
-8.7 链表(四)
-8.8 函数指针(一)
-8.9 函数指针(二)
-8.10 抽象链表(一)
-8.11 抽象链表(二)
-8.12 编程实践
-第八讲 链表与程序抽象--编程实践提交入口
-9.1 提纲
-9.2 程序抽象与面向对象
-9.3 类类型
-9.4 对象(一)
-9.5 对象(二)
-9.6 类与对象的成员(一)
-9.7 类与对象的成员(二)
-9.8 类与对象的成员(三)
-9.9 继承(一)
-9.10 继承(二)
-9.11 继承(三)
-9.12 多态(一)
-9.13 多态(二)
-9.14 编程实践
-第九讲 类与对象--编程实践提交入口
-10.1 提纲
-10.2 四则运算符重载(一)
-10.3 四则运算符重载(二)
-10.4 关系与下标操作符重载
-10.5 赋值操作符重载(一)
-10.6 赋值操作符重载(二)
-10.7 赋值操作符重载(三)
-10.8 赋值操作符重载(四)
-10.9 赋值操作符重载(五)
-10.10 流操作符重载(一)
-10.11 流操作符重载(二)
-10.12 流操作符重载(三)
-10.13 操作符重载总结
-10.14 编程实践
-第十讲 操作符重载--编程实践提交入口
-11.1 提纲
-11.2 泛型编程概览
-11.3 异常处理机制(一)
-11.4 异常处理机制(二)
-11.5 运行期型式信息(一)
-11.6 运行期型式信息(二)
-11.7 模板与型式参数化
-11.8 题外话:术语翻译
-11.9 泛型编程实践(一)
-11.10 泛型编程实践(二)
-11.11 泛型编程实践(三)
-11.12 泛型编程实践(四)
-11.13 泛型编程实践(五)
-11.14 泛型编程实践(六)
-11.15 泛型编程实践(七)
-11.16 泛型编程实践(八)
-11.17 泛型编程实践(九)
-11.18 泛型编程实践(十)
-11.19 编程实践
-第十一讲 泛型编程--编程实践提交入口
-12.1 提纲
-12.2 程序执行环境(一)
-12.3 程序执行环境(二)
-12.4 程序执行环境(三)
-12.5 程序执行环境(四)
-12.6 输入输出(一)
-12.7 输入输出(二)
-12.8 文件系统
-12.9 设备
-12.10 库(一)
-12.11 库(二)
-12.12 makefile文件(一)
-12.13 makefile文件(二)
-12.14 makefile文件(三)
-12.15 编程实践
-第十二讲 Linux系统编程基础--编程实践提交入口
-13.01 提纲
-13.02 进程基本概念
-13.03 信号
-13.04 进程管理(一)
-13.05 进程管理(二)
-13.06 进程管理(三)
-13.07 进程间通信(一)
-13.08 进程间通信(二)
-13.09 进程间通信(三)
-13.10 进程间通信(四)
-13.11 进程池
-13.12 编程实践
-第十三讲 进程编程--编程实践提交入口
-14.1 提纲
-14.2 线程基本概念
-14.3 线程管理(一)
-14.4 线程管理(二)
-14.5 线程管理(三)
-14.6 线程管理(四)
-14.7 线程同步机制(一)
-14.8 线程同步机制(二)
-14.9 C++11线程库(一)
-14.10 C++11线程库(二)
-14.11 C++11线程库(三)
-14.12 C++11线程库(四)
-14.13 C++11线程库(五)
-14.14 编程实践
-第十四讲 线程编程--编程实践提交入口
-15.1 提纲
-15.2 Internet网络协议
-15.3 套接字(一)
-15.4 套接字(二)
-15.5 编程实践
-第十五讲 网络编程--编程实践提交入口