网站建设深圳赶集网,呼叫中心外包,psd网站排行榜,抖音黑科技引流推广神器概念 是操作系统提供给用户使其可以操作内核提供服务的一组函数接口。 用户态和内核态#xff1a; 引入 #xff1a; 整个 计算机系统 的。好比你写 一个程序#xff0c;但是因为你对 硬件操作 不熟悉#xff0c;出现 问题#xff0c;那么影响范围是多大#xff1f;是整…概念 是操作系统提供给用户使其可以操作内核提供服务的一组函数接口。 用户态和内核态 引入 整个 计算机系统 的。好比你写 一个程序但是因为你对 硬件操作 不熟悉出现 问题那么影响范围是多大是整个计算机系统操作系统内核、及其其他所有正在运 行的程序都会因为你操作失误而受到不可挽回的错误那么你只有重启整个计算机才 行 而对于 硬件的操作 是非常复杂的参数众多出问题的几率相当大必须及其谨 慎的进行操作这对于个人开发者来说是个艰巨的任务同时个人开发者在这方面也是 不被信任的。所以 操作系统内核 直接屏蔽了个人开发者对于硬件操作的可能. 这方面 系统内核 对 硬件操作 进行了封装处理对外提供标准函数库操作更简 单、更安全。比如 我们要打开一个文件C 标准函数库中对应的是 fopen() 其内部封 装的是内核中的系统函数open() 因为这个需求硬件设备商直接提供了硬件级别的支持做法就是对 CPU 指令设置了 权限不同级别的权限可以使用的 CPU 指令是有限制的。以 Inter CPU 为例 Inter 把 CPU 指令操作的权限划为 4 级 ring 0 ring 1 ring 2 ring 3 其中 ring 0 权限最高可以使用所有 CPU 指令 ring 3 权限最低仅能使用 常规 CPU 指令这个级别的权限不能使用访问硬件资源的指令比如 IO 读写、网卡 访问、申请内存都不行都没有权限 Linux 系统内核采用了 ring 0 和 ring 3 这 2 个权限 ring 0: 内核态 , 完全在 操作系统内核 中运行由专门的 内核线程 在 CPU 中 执行其任务 ring 3: 用户态 , 在 应用程序 中运行由 用户线程 在 CPU 中执行其任务 Linux 系统中所有对硬件资源的操作都必须在 内核态 状态下执行比如 IO 的 读写网络的操作 区别 1,用户态的代码必须由 用户线程 去执行、内核态的代码必须由 内核线程 去执行 2,用户态、内核态 或者说 用户线程、内核线程 可以使用的资源是不同的尤体现在 内存资源上。Linux 内核对每一个进程都会分配 4G 虚拟内存空间地址 用户态 -- 只能操作 0-3G 的内存地址 内核态 -- 0-4G 的内存地址都可以操作尤其是对 3-4G 的高位地址必须由 内核态去操作因为所有进程的 3-4G 的高位地址使用的都是同一块、专门留给 系统 内核 使用的 1G 物理内存 3.所有对 硬件资源、系统内核数据 的访问都必须由内核态去执行 如何切换内核态 通过软件中断 软件中断 软件中断是由软件程序触发的中断如系统调用、软中断、异常等。软件中断不是 由硬件设备触发的而是由软件程序主动发起的一般用于系统调用、进程切换、异常 处理等任务。软件中断需要在程序中进行调用其响应速度和实时性相对较差但是具 有灵活性和可控性高的特点。 如程序中出现的内存溢出, 数组下标越界等 硬件中断 硬件中断是由硬件设备触发的中断如时钟中断、串口接收中断、外部中断等。当 硬件设备有数据或事件需要处理时会向CPU 发送一个中断请求 CPU 在收到中断请求 后会立即暂停当前正在执行的任务进入中断处理程序中处理中断请求。硬件中断具 有实时性强、可靠性高、处理速度快等特点。 如当点击按钮扫描系统高低电频时等 系统调用与库函数的关系 库函数可以调用系统调用提供的接口 , 也可以不调用系统调用提供的接口 如 不调用系统调用的库函数:strcpy,bzero 等 调用系统调用的库函数:fread,printf 等 注意 : 系统调用是需要时间的程序中频繁的使用系统调用会降低程序的运行效率。当运行内核 代码时CPU 工作在内核态在系统调用发生前需要保存用户态的栈和内存环境然后转 入内核态工作。系统调用结束后又要切换回用户态。这种环境的切换会消耗掉许多时 间。 文件操作 文件描述符概念 文件描述符是一个非负整数, 代表已打开的文件。 每一个进程都会创建一张文件描述符表 记录的是当前进程打开的所有文件描述符。 每一个进程默认打开三个文件描述符 0(标准输入设备 scanf) 1(标准输出设备 printf) 2(标准错误输入设备 perror) 。 新打开的文件描述符 为最小可用文件描述符。 扩展 ulimit是一个计算机命令用于 shell 启动进程所占用的资源可用于修改系统资源限 制。使用ulimit 命令用于临时修改资源限制如果需要永久修改需要将设置写入配置文 件/etc/security/limits.conf 。 ulimit -a 查看 open files 打开的文件最大数。 ulimit -n 最大数 设置 open files 打开的文件最大数。 文件读写 第一位说是文件还是文件夹 2~4位说明所有者权限 5~7位说明同组用户权限 8~10位说明其他用户权限 r 4 w 2 x 1 注意 man 2 系统调用 查看系统调用函数对应的头文件与函数信息 语法 : open: 打开文件 所需头文件 #include sys/types.h #include sys/stat.h #include fcntl.h 函数 int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 参数 pathname:打开的文件地址 flags:代码操作文件的权限 必选项 O_RDONLY 以只读的方式打开 O_WRONLY 以只写的方式打开 O_RDWR 以可读、可写的方式打开 可选项 O_CREAT 文件不存在则创建文件使用此选项时需使用 mode 说明文件的权限 O_EXCL 如果同时指定了 O_CREAT 且文件已经存在 , 则打开 , 如果文件 不存在则新建 O_TRUNC 如果文件存在则清空文件内容 O_APPEND 写文件时数据添加到文件末尾 O_NONBLOCK 对于设备文件 , 以 O_NONBLOCK 方式打开可以做非阻塞 I/O mode: 文件在磁盘中的权限 格式 : 0ddd d的取值 :4( 可读 ),2( 可写 ),1( 可执行 ) 第一个 d: 所有者权限 第二个 d: 同组用户权限 第三个 d: 其他用户权限 如果需要可读可写就是 6, 可读可执行 5 等 如 : 0666:所有者可读可写 , 同组用户可读可写 , 其他用户可读可写 0765:所有者可读可写可执行 , 同组用户可读可写 , 其他用户可读可执行 返回值 成功得到最小可用的文件描述符 失败-1 经验 : 操作已有文件使用两参 新建文件使用三参 close 关闭文件 所需头文件 #include unistd.h 函数 int close(int fd); 参数 关闭的文件描述符 返回值 成功0 失败 -1, 并设置 errno 示例 : 以只读的方式打开关闭文件 #include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
int main(int argc, char const *argv[])
{//1打开文件// man 2 系统调用函数名// int open(const char *pathname, int flags);// int open(const char *pathname, int flags, mode_t mode);int fileTag open(a.txt,O_RDONLY);if (fileTag 0){printf(读取文件不存在,文件标识符为:%d\n,fileTag);return 0;}printf(文件打开成功,文件标识符为:%d\n,fileTag);int tag close(fileTag);if (tag 0){printf(关闭文件失败\n);}else{printf(关闭文件成功\n);}return 0;
} 示例 : 以写的方式打开关闭文件 #include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
int main(int argc, char const *argv[])
{//1打开文件// man 2 系统调用函数名// int open(const char *pathname, int flags);// int open(const char *pathname, int flags, mode_t mode);int fileTag open(a.txt,O_WRONLY| O_CREAT, 0644);if (fileTag 0){printf(文件不存在,文件标识符为:%d\n,fileTag);return 0;}printf(文件打开成功,文件标识符为:%d\n,fileTag);int tag close(fileTag);if (tag 0){printf(关闭文件失败\n);}else{printf(关闭文件成功\n);}return 0;
} write 写入 所需头文件 #include unistd.h 函数 ssize_t write(int fd, const void *buf, size_t count); 参数 fd:写入的文件描述符 buf:写入的内容首地址 count:写入的长度 , 单位字节 返回值 成功: 返回写入的内容的长度 , 单位字节 失败:-1 示例 #include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
int main(int argc, char const *argv[])
{int fileTag open(a.txt,O_WRONLY| O_CREAT | O_APPEND, 0744);if (fileTag 0){printf(文件不存在,文件标识符为:%d\n,fileTag);return 0;}char str[] hello;int len write(fileTag,str,sizeof(str)-1);if(len 0){printf(写入失败\n);}else{printf(写入成功len %d,%d\n,len,sizeof(str));}int tag close(fileTag);if (tag 0){printf(关闭文件失败\n);}else{printf(关闭文件成功\n);}return 0;
} read 读取 所需头 #include unistd.h 函数 ssize_t read(int fd, void *buf, size_t count); 参数 fd:文件描述符 buf:内存首地址 count:读取的字节个数 返回值 成功: 实际读取到的字节个数 失败:-1 示例 #include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
int main(int argc, char const *argv[])
{int id open(a.txt,O_RDONLY);if(id 0){printf(文件打开失败\n);return 0;}char buf[50] ;int len read(id,buf,sizeof(buf));printf(%s,buf);if (close(id) 0){printf(文件关闭失败\n);}return 0;
} 示例 : 文件复制 #include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
int main(int argc, char const *argv[])
{int fd_r open(a.txt,O_RDONLY);if(fd_r 0){printf(读取文件打开失败\n);return 0;}int fd_w open(b.txt,O_WRONLY|O_CREAT|O_APPEND,0666);if(fd_w 0){printf(写入文件打开失败\n);return 0;}while (1){char buf[3] ;int len read(fd_r,buf,sizeof(buf));int size write(fd_w,buf,len);if (len sizeof(buf)){break;}}if (close(fd_w) 0){printf(写入文件关闭失败\n);}if (close(fd_r) 0){printf(读取文件关闭失败\n);}printf(OVER\n);return 0;
} 文件的阻塞特性 read默认为阻塞。如果读不到数据将阻塞不继续执行 知道有数据可读才继续往下 执行。 非阻塞特性如果没数据立即返回继续执行。 注意: 阻塞与非阻塞是对于文件而言的而不是指 read 、 write 等的属性。 #include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
int main(int argc, char const *argv[])
{//dev:liunx设备存储文件夹//tty:终端///dev/tty:表示当前终端int fd open(/dev/tty,O_RDONLY);//O_NONBLOCK:设置打开的文件为非阻塞// int fd open(/dev/tty,O_RDONLY|O_NONBLOCK);char buf[32] ;printf(开始读取\n);read(fd,buf,sizeof(buf));printf(读取结束\n);return 0;
} 通过 open 打开的文件可以设置非阻塞 , 但是如果不是通过 open 打开的文件怎么办 ? 通过 fcntl 函数来解决 funtl 作用 : 针对已经存在的文件描述符设置阻塞状态 所需头文件 #include unistd.h #include fcntl.h 函数 : int fcntl(int fd, int cmd, ... /* arg */); 功能 : 改变已打开的文件性质 fcntl 针对描述符提供控制。 参数 fd 操作的文件描述符 cmd 操作方式 arg 针对 cmd 的值 fcntl 能够接受第三个参数 int arg 。 返回值 成功返回某个其他值 失败 -1 fcntl 函数有 5 种功能 1) 复制一个现有的描述符 cmdF_DUPFD 2) 获得设置文件描述符标记 (cmdF_GETFD 或 F_SETFD) 3) 获得设置文件状态标记 (cmdF_GETFL 或 F_SETFL) 4) 获得设置异步 I/O 所有权 (cmdF_GETOWN 或 F_SETOWN) 5) 获得设置记录锁 (cmdFGETLK, F_SETLK 或 F_SETLKW) 使用步骤 1,获取文件状态标记 2,将得到的文件状态标记设置为非阻塞 3,将修改后的文件非阻塞状态标记 , 设置到当前文件描述符中 #include stdio.h
#include unistd.h
#include fcntl.h
int main(int argc, char const *argv[])
{
//1,获取文件标记状态
int status fcntl(0,F_GETFL);
//2修改状态为非阻塞状态
status status | O_NONBLOCK;
//3,设置文件标记状态为非阻塞状态
fcntl(0,F_SETFL,status);
char buf[32];
printf(开始读取\n);
//0(标准输入设备scanf)
int len read(0,buf,sizeof(buf));
printf(结束读取,读取到的内容为:%s\n,buf);
return 0;
} 文件状态 语法 作用 : 获取文件状态信息 所需头 #include sys/types.h #include sys/stat.h #include unistd.h 函数 int stat(const char *path, struct stat *buf); int lstat(const char *pathname, struct stat *buf); 参数 1参 : 文件地址 2参 : 保存文件信息的结构体 返回值 0:成功 -1:失败 stat 与 lstat 的区别 当文件是一个符号链接时 lstat 返回的是该符号链接本身的信息 , stat 返回的是该链接指向的文件的信息。 stat 结构体解释 struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为 1
uid_t st_uid; //用户 ID
gid_t st_gid; //组 ID
dev_t st_rdev; //(设备类型)若此文件为设备文件则为其设备编号
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize; //块大小(文件系统的 I/O 缓冲区大小)
blkcnt_t st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
}; stat 结构体 st_mode 属性 一个由16 个字节组成 , 简称 16 位 0~2其他人权限 3~5所属组权限 6~8所有者权限 12~15文件类型 具体参考下图 存储权限 S_ISUID 04000 set-user-ID bit S_ISGID 02000 set-group-ID bit (see below) S_ISVTX 01000 sticky bit (see below) S_IRWXU 00700 owner has read, write, and execute permission S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 group has read, write, and execute permission S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 others (not in group) have read, write, and execute permission S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permission S_IXOTH 00001 others have execute permission #include stdio.h
#include sys/types.h//open
#include sys/stat.h//open
#include fcntl.h//open
#include unistd.h//close
int main(int argc, char *argv[])
{
//获取文件状态
struct stat st;
stat(a.txt, st);
//分析文件类型
if(S_ISREG(st.st_mode))
{
printf(普通文件\n);
}
else if (S_ISDIR(st.st_mode))
{
printf(目录文件\n);
}
//分析权限
if((st.st_mode S_IRUSR) S_IRUSR )
{
printf(所有者具有读权限\n);
}
if((st.st_mode S_IWUSR) S_IWUSR)
{
printf(所有者具有写权限\n);
}
if((st.st_mode S_IXUSR) S_IXUSR)
{
printf(所有者具有执行权限\n);
}
printf(文件的大小:%ld\n, st.st_size);
return 0;
} 目录操作 语法 打开目录 作用 : 打开目录 opendir 所有头文件 : #include sys/types.h #include dirent.h 函数 : DIR *opendir(const char *name); 参数 name目录名 返回值 成功返回指向该目录结构体指针(DIR *) 失败NULL DIR: 中文名称句柄 , 其实就是目录的结构体指针 读取目录 作用 : 读取目录 readdir 所需头文件 #include dirent.h 函数 struct dirent *readdir(DIR *dirp); 参数 dirp opendir 的返回值 返回值 成功目录结构体指针 失败NULL 注意 : 一次读取一个文件。 相关结构体 相关结构体说明 struct dirent { ino_t d_ino; // 此目录进入点的 inode off_t d_off; // 目录文件开头至此目录进入点的位移 signed short int d_reclen; // d_name 的长度 , 不包含 NULL 字符 unsigned char d_type; // d_type 所指的文件类型 char d_name[256]; // 文件名 }; d_type 说明 : DT_BLK 这是一个块设备。 ( 块设备如 : 磁盘 ) DT_CHR 这是一个字符设备。 ( 字符设备如 : 键盘 , 打印机 ) DT_DIR 这是一个目录。 DT_FIFO 这是一个命名管道 FIFO 。 DT_LNK 这是一个符号链接。 DT_REG 这是一个常规文件。 DT_SOCK 这是一个 UNIX 域套接字。 DT_UNKNOWN 文件类型未知。 关闭目录 作用 : 关闭目录 closedir 所需头文件 #include sys/types.h #include dirent.h 函数 int closedir(DIR *dirp); 参数 dirp:opendir 返回的指针 返回值 成功0 失败-1 示例扫描文件目录 #include stdio.h
#include sys/types.h
#include dirent.h
int main(int argc, char const *argv[])
{
DIR *dir opendir(./);
if(dir NULL)
{
printf(打开文件夹失败);
return 0;
}
while(1)
{
struct dirent * d readdir(dir);
if (d NULL)
{
break;
}
if (d-d_type DT_DIR)
{
printf(%s是个文件夹\n,d-d_name);
}
else if(d-d_type DT_REG)
{
printf(%s是个普通文件\n,d-d_name);
}
}
return 0;
} #include stdio.h
#include sys/types.h
#include dirent.h
#include string.h
void blDIR(char *path)
{
char filedir[128];
strcpy(filedir,path);
DIR *dir opendir(filedir);
if(dir NULL)
{
printf(打开文件夹失败);
return;
}
while(1)
{
struct dirent * d readdir(dir);
if (d NULL)
{
break;
}
/**
* strcmp(字符串1,字符串2):比较字符串是否相同
* strcat(字符串1,字符串2):将字符串2拼接到字符串1后
*/
if (d-d_type DT_DIR strcmp(d-d_name,.) ! 0
strcmp(d-d_name,..) !0)
{
printf(%s是个文件夹\n,d-d_name);
strcat(filedir,/);
strcat(filedir,d-d_name);
blDIR(filedir);
}
else if(d-d_type DT_REG)
{
printf(%s是个普通文件\n,d-d_name);
}
}
closedir(dir);
}
int main(int argc, char const *argv[])
{
blDIR(./);
return 0;
}