字符设备、块设备和网络设备

在Linux内核中,设备分为几类,最常见的包括字符设备、块设备和网络设备。它们各自有不同的功能和使用场景。下面是对这些设备类型的概念、特点及常见例子的详细说明。

字符设备

字符设备是一个能够像字节流一样被访问的设备,由字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少要实现打开、关闭、读取和写入系统调用。
字符设备是一个顺序访问的,只有在设备响应后才能读到相应信息。
不能随机访问,且每个字符设备都有一个设备号,设备号由主设备号和次设备号组成。常见的字符设备如串口、IIC等。
字符设备的对应的文件都在/dev目录下,每一个文件对应一个硬件。在linux系统中/dev目录下使用ls -l命令查看详细信息,第一个字母“c”为字符设备文件的标识。
在这里插入图片描述

特点:

顺序读写:字符设备以字节为单位进行顺序读写,不支持随机访问。
实时性强:通常用于与实时设备交互,适合处理实时数据。
无缓存:字符设备没有类似块设备那样的缓存功能,数据直接传输。

常见例子:

串口设备:如 /dev/ttyS0,用于与串行设备(如调制解调器)进行通信。
终端设备:如 /dev/tty,用于用户与操作系统之间的交互。
随机数生成器:如 /dev/random 和 /dev/urandom,用于生成伪随机数。
音频设备:如 /dev/dsp,用于处理音频输入/输出。
鼠标和键盘设备:如 /dev/input/mice 和 /dev/input/event0,用于处理用户输入设备的数据。

块设备 (Block Devices)

和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。
块设备上能够容纳文件系统。常见的块设备如磁盘、emmc flash、nand flash、 SD卡等。每个块设备同样有r–+’/h涡阳【5片【一个设备号,设备号由主设备号和次设备号组成。在linux系统中/dev目录下使用ls -l命令查看详细信息,第一个字母“b”为块设备文件的标识。/dev下每个块设备文件对应一个磁盘的分区。

在这里插入图片描述
块设备是一类以数据块为单位进行读写操作的设备。块设备通常用于存储设备,支持大规模数据的处理,并且能够进行随机读写。数据在块设备上通过块(通常为512字节或更大)传输,块设备通常带有缓存功能,能够优化大数据量的存取操作。

特点:

随机读写:块设备允许以数据块为单位进行随机读写操作,适合处理大容量数据。
缓存支持:数据可以先写入缓存,再批量写入存储设备,提升性能。
适用于存储设备:块设备通常用于磁盘存储、分区等场景。

常见例子:

硬盘设备:如 /dev/sda,用于连接硬盘或固态硬盘的设备节点。
分区设备:如 /dev/sda1,表示硬盘的逻辑分区。
USB存储设备:如 /dev/sdb,用于管理外部USB存储设备。
光驱设备:如 /dev/sr0,用于CD/DVD驱动器的设备节点。

网络设备 (Network Devices)

任何网络相关的事务都要经过一个网络接口,即一个能够与其他主机交换数据的设备。通常,接口是个硬件设备,但也可能是纯软件设备,比如在ifconfig查看网口信息的时候有一个lo,就是网络回环(loopback)接口。访问网络接口的方法是给它们分配一个唯一的名字,比如eth0、eth1、lo等。但这个名字在文件系统中不存在相应的节点。
网络接口没有像字符设备和块设备一样的设备号,只有一个唯一的名字,如eth0、eth1等,而这个名字也不需要与设备文件节点对应。内核使用一套与数据包传输相关的函数来与网络设备驱动程序通信,它们不同于字符设备和块设备的read()和write()方法。
在这里插入图片描述
网络设备是一类用于网络通信的设备,它们与字符设备和块设备不同,不直接涉及文件系统,而是用于通过网络传输数据。网络设备使用专门的协议栈(如TCP/IP协议)来处理数据的封装、传输和解封装,广泛用于局域网、广域网和互联网的数据交换。

特点:

基于协议栈:网络设备通过TCP/IP等协议进行数据传输和管理。
数据包处理:网络设备处理的是数据包,数据以帧或包的形式在网络中传输。
虚拟网络设备:支持各种虚拟网络设备,如虚拟网卡和隧道接口。

常见例子:

以太网设备:如 eth0,用于有线网络通信的网卡设备。
无线网卡:如 wlan0,用于无线网络通信的设备。
环回接口:如 lo,用于本地回环测试的虚拟网络设备。
虚拟网络接口:如 tun0,用于VPN等场景下的数据隧道接口。

设备类型的主要区别

字符设备通过逐字节处理数据,适用于小数据量和实时数据的处理,适合用户输入、音频、串口通信等场景。
块设备通过块(数据块)进行读写,支持随机存取和缓存管理,通常用于存储和处理大数据量,如硬盘、分区等存储设备。
网络设备负责数据在网络中的传输,通过数据包和协议栈进行处理,适合用于网络通信、数据传输等。

在这里插入图片描述

### 字符设备块设备网络设备的定义及其区别 #### 字符设备 字符设备是一种按照字符流的方式进行有序访问的设备。这类设备通常不支持随机访问,而是按顺序逐个字符地进行数据的读取或写入。常见的字符设备包括串口、键盘鼠标等。字符设备的驱动程序通常负责处理这类设备的输入输出操作,且其数据传输以字节流的形式进行,不涉及缓存或缓冲机制。 #### 块设备 块设备是一种支持随机访问的设备,通常以固定大小的数据块为单位进行读写操作。块设备的特点是能够直接访问存储介质上的任意位置,例如硬盘、固态硬盘(SSD)光盘驱动器等。块设备的驱动程序需要处理数据的缓存调度,以优化数据访问效率。Linux内核中的块设备子系统负责管理这类设备的数据传输缓存机制。 #### 网络设备 网络设备是一种用于数据包在网络媒介上发送接收的设备。与字符设备块设备不同,网络设备并不直接对应于`/dev`目录下的文件,而是通过套接字接口与应用程序进行交互。网络设备的驱动程序需要实现数据包的发送接收功能,并与上层协议栈进行数据交互。Linux内核将网络设备驱动分为四个层次:网络协议接口层、网络设备接口层、设备驱动功能层网络设备与媒介层。 --- ### 三者的区别 #### 数据访问方式 - **字符设备**:按照字符流的方式进行有序访问,数据传输以字节流的形式进行。 - **块设备**:支持随机访问,数据传输以固定大小的数据块为单位。 - **网络设备**:以数据包的形式进行传输,支持网络协议栈的数据交互。 #### 数据传输特性 - **字符设备**:通常不涉及缓存机制,数据传输直接进行。 - **块设备**:涉及数据缓存调度机制,以优化数据访问效率。 - **网络设备**:需要实现数据包的封装解封装,并与上层协议栈进行交互。 #### 驱动开发特点 - **字符设备驱动**:主要处理字符流的读写操作,通常较为简单。 - **块设备驱动**:需要实现数据缓存调度功能,以提高存储设备的访问效率。 - **网络设备驱动**:需要实现数据包的发送接收功能,并与上层协议栈进行交互。 #### 应用场景 - **字符设备**:适用于键盘、鼠标、串口等需要逐个字符处理的设备。 - **块设备**:适用于硬盘、固态硬盘(SSD)等存储设备。 - **网络设备**:适用于网卡、无线网卡等网络接口设备。 --- ### 示例代码:字符设备驱动的基本结构 ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #define DEVICE_NAME "my_char_device" #define BUF_LEN 100 static int major_number; static struct cdev my_cdev; static char msg[BUF_LEN]; static int device_open(struct inode *inode, struct file *file) { printk(KERN_INFO "Device opened\n"); return 0; } static int device_release(struct inode *inode, struct file *file) { printk(KERN_INFO "Device closed\n"); return 0; } static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { int bytes_read = 0; if (*offset >= BUF_LEN) return 0; while (length && (*offset < BUF_LEN)) { put_user(msg[*offset], buffer++); length--; (*offset)++; bytes_read++; } return bytes_read; } static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { int i; for (i = 0; i < length && i < BUF_LEN; i++) { get_user(msg[i], buffer + i); } *offset += i; return i; } static struct file_operations fops = { .read = device_read, .write = device_write, .open = device_open, .release = device_release, }; static int __init char_device_init(void) { dev_t dev_num; int ret; ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME); if (ret < 0) { printk(KERN_ERR "Failed to allocate char device region\n"); return ret; } major_number = MAJOR(dev_num); cdev_init(&my_cdev, &fops); ret = cdev_add(&my_cdev, dev_num, 1); if (ret < 0) { printk(KERN_ERR "Failed to add char device\n"); unregister_chrdev_region(dev_num, 1); return ret; } printk(KERN_INFO "Char device registered with major number %d\n", major_number); return 0; } static void __exit char_device_exit(void) { cdev_del(&my_cdev); unregister_chrdev_region(MKDEV(major_number, 0), 1); printk(KERN_INFO "Char device unregistered\n"); } module_init(char_device_init); module_exit(char_device_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple character device driver"); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值