首页 > 系统相关 >2024-02-21-物联网Shell语言(2-系统调用)

2024-02-21-物联网Shell语言(2-系统调用)

时间:2024-02-22 14:25:16浏览次数:25  
标签:02 文件 Shell int 2024 描述符 调用 fd include

2.系统调用

2.1 系统编程概述

操作系统的职责:操作系统用来管理所有的资源,并将不同的设备和不同的程序关联起来

Linux系统编程:在有操作系统打的环境下编程,并使用操作系统提供的系统调用及库函数,对系统资源进行访问

系统编程就是为了让用户更方便的操作硬件设备,并且对硬件设备起到保护作用。我们所写的程序,本质就是对硬件设备的操作。

2.2 系统调用概述

image-20210822152235927 image-20240221172709674

系统调用本质上是对硬件设备进行操作,但是linux操作系统在硬件之上设置了内核,这样只有内核才可以直接对硬件设备进行操作。

如果想操作内核,需要使用内核的系统调用,手段有以下三种:

  1. shell,用户通过shell命令,经由shell解释器与操作内核的系统调用
  2. 库函数,用户通过应用层库函数接口,对内核的系统调用进行操作
  3. 应用层系统调用,直接对内核系统调用进行操作

系统调用是操作系统提供给用户程序的一组"特殊"的函数接口

系统调用按照功能逻辑分为:

  1. 进程控制
  2. 进程间通信
  3. 文件系统控制
  4. 系统控制
  5. 内存管理
  6. 网络管理
  7. socket控制
  8. 用户管理

系统调用的返回值:

  • 返回值为0 ,成功
  • 返回值为负数,错误,错误信息存放在errno中,用户可以通过perror函数打印出错信息

系统调用遵循的规范:在linux中,应用程序编程接口(API)遵循POSIX标准

2.3 系统调用I/O函数

2.3.1 文件描述符

系统调用中操作I/O函数,都是针对文件描述符的。

文件描述符是非负整数,打开现存的文件或者新建文件时,系统(内核)会返回一个文件描述符。

当一个程序运行或者一个进程开启时,系统会自动创建三个文件描述符。

文件描述符 标准IO 说明
0 stdin 标准输入
1 stdout 标准输出
2 stderr 标准输出错误

2.3.2 open函数

打开一个文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 当文件存在时,使用 
int open(const char *pathname, int flag);

// 当文件不存在时使用
int open(const char *pathname,int flags, mode_t mode);

参数:
    pathname: 文件路径及文件名;
	flags:open函数的行为标志;
	mode:文件权限(可读可写可执行)的设置;
返回值:
    成功,返回打开文件的描述符
    失败, 返回-1,可以利用perror查看原因

flags的取值和含义

取值 含义
O_RDONLY 以只读方式打开
O_WRONLY 以只写方式打开
O_RDWR 以可读可写方式打开

flags除了上述取值外,还可以与下列值位或

取值 含义
O_CREAT 文件不存在时创建文件;使用此选项需要使用mode说明文件权限
O_EXCL 如果同时指定O_CREAT,且文件已经存在,则出错
O_TRUNC 如果文件存在,则清空文件内容
O_APPEND 写文件时,数据添加到文件末尾
O_NOBLOCK 非阻塞标志位(文件类型为FIFO、字符文件、块文件)

mode ,只有当flag含有O_CREAT时,才能使用,取值如下(可以用八进制数代替):

取值 八进制数 含义
S_IRWXU 00700 可读可写可执行
S_IRUSR 00400 文件所有者可读
S_IWUSR 00200 文件所有者可写
S_IXUSR 00100 文件所有者可执行
S_IRWXG 00070 文件所有者组内可读可写可执行
S_IRGRP 00040 文件所有者组内可读
S_IWGRP 00020 文件所有者组内可写
S_IXGRP 00010 文件所有者组内可执行
S_IRWXO 00007 其他组用户可读可写可执行
S_IROTH 00004 其他组用户可读
S_IWOTH 00002 其他组用户可写
S_IXOTH 00001 其他组用户可执行

文件IO和标准IO权限对比

标准IO 文件IO 权限含义
r O_RDONLY 只读方式打开,文件不存在则报错
r+ O_RDWR 读写方式打开文件,文件不存在则报错
w O_WRONLY | O_CREAT | O_TRUNC,0644 只读方式打开,文件不存在则创建,存在则清空
w+ O_RDWR | O_CREAT | O_TRUNC, 0644 读读方式打开,文件不存在则创建,存在则清空
a O_WEONLY | O_CREAT | O_APPEND, 0644 只写方式打开,文件不存在则创建,存在则追加
a+ O_RDWR | O_CREAT | O_APPEND, 0644 读写方式打开,文件不存在则创建,存在则追加
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    
    int fd;
    //  使用open函数打开一个文件
    fd = open("file.txt",O_RDONLY | O_CREAT,0664);
    printf("fd = %d",fd);
    return 0;
}

输出结果,会创建一个新文件file.txt

fd = 3

函数调用出错后输出错误信息

通过全局变量errno
    #include <errno.h>
    errno是一个全局变量,当函数调用失败后,可以通过errno获取错误码
通过一个函数perror
    #include <stdio.h>
    功能:输出函数调用失败后的错误信息
    参数:
    	s : 打印错误信息的提示消息
    返回值:无
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char const *argv[])
{

    int fd;
    //  使用open函数打开一个文件
    fd = open("file.txt", O_RDONLY);
    printf("error = %d\n", errno);
    perror("fail to open"); // 使用perror打印错误信息
    return 0;
}

输出结果

error = 2	// 文件不存在的错误码
fail to open: No such file or directory // 文件不存在,直接打印出出错信息

2.3.3 close函数

关闭一个文件

#include <unistd.h>
int close(int fd)
功能:关闭一个文件描述符
参数:
    fd:指定文件的文件描述符,即open函数的返回值
返回值:
    成功:0
    失败:1
#include <stdio.h>
#include <sys/fcntl.h>

int main(int argc, char const *argv[])
{
    int fd;
    fd = open("file.txt", O_RDONLY);
    if (fd == -1)
    {
        perror("fail to open");
        return -1;
    }
    else
    {
        printf("fd = %d\n", fd);
        // 当不对文件操作的时候,就会关闭文件描述符
        // 使用close函数关闭文件描述符
        // 一旦文件描述符关闭,就不能通过原有的文件描述符对文件进行操作
        close(fd);
    }

    return 0;
}

输出结果

fd = 3

注意

  1. 程序运行的时候,最多创建1024个文件描述符,值范围是 0 -1023

  2. 文件描述符从小到大依次递增

  3. 如果中途有文件描述符被关闭,则会再创建;新建的文件描述符会使用前面空缺的文件描述符,前面不空缺,则依次递增

    如已有文件描述符 1 2 3 4 5 7 
        这是 4 被关闭,只剩下 1 2 3 5 7,新创建两个文件描述符,第一个就是 4,第二个为 8;  
    

2.3.4 write 函数

把执行数目的数据写入文件

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:向文件写入数据
参数:
	fd:指定的文件描述符
	buf:要写入的数据
	count:要写入的数据的长度
返回值:
	成功:实际写入的字节数
	失败:-1

向终端写入内容

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    // 向终端写入数据,对1这个文件描述符进行操作,标准输出
    if(write(1,"hello world!",12) == -1){
        perror("fail to write");
        return -1;
    }
    return 0;
}

输出结果

hello world!

向文件写入内容

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    // 向文件写数据
    int fd;
    // 以只写的方式打开文件,文件不存在则创建,文件存在则清空
    fd = open("file.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1)
    {
        perror("fail to open");
        return -1;
    }

    if (write(fd, "hello world!\n", 12) == -1)
    {
        perror("fail to write");
        return -1;
    }
    close(fd);
    return 0;
}

输出结果,创建了文件file.txt

file.txt

hello world!

2.3.5 read函数

把指定数目的数据读取到内存

把指定数目的数据读到内存
#include <unistd, h>
ssize_t read(int fd, void *addr, size_t count);
参数:
	fd:攻件描述符
	addr:内存首地址
	count;读取的字节个数
返回值:
	成功:返回实际读取到的字节个数
	失败:返回-1,可以利用 perror获取原因
     注意:如果读取到末尾,返回0

从终端读取数据

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int main(int argc, char const *argv[])
{
    // 从终端读取数据,使用文件描述符0
    char str[32] = "";
    if (read(0, str, 6) == -1) // 此处定义了保存多少个字节
        // 此处定义的数据大于输入数据,则输出数据位原数据 + 一个换行符
    {
        perror("fail to read");
        return -1;
    }
    printf("str = [%s]\n",str);
    return 0;
}

输出结果

hello world
str = [hello ] //保存了6个字符

从文件读取数据

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

#define N 64
int main(int argc, char const *argv[])
{
    // 从文件读取数据
    int fd;
    if ((fd = open("text.txt", O_RDONLY | O_CREAT, 0664)) == -1)
    {
        perror("fail to read");

        return -1;
    }
    // 读取文件内容
    char buf[N] = "";
    if ((read(fd, buf, 32)) == -1)
    {
        perror("fail to read");
        return -1;
    }
    printf("buf = [%s]", buf);
    close(fd);

    return 0;
}

输出结果

buf = [HELLO WORLD]

2.3.6 remove

删除文件

#include<stdio.h>
int remove(const char *pathname)
    参数: 文件的路名+文件名pathname :
返回值:
	成功返回 0。
	失败返回-1,可以利用 perror 去查看原因
#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 使用remove函数删除文件
    if (remove("./file.txt") == -1)
    {
        perror("fail to remove");
        return -1;
    }
    printf("delete done\n");
    return 0;
}

输出结果

delete done

2.4系统调用与库函数对比

库函数有两类函数组成:

  1. 不需要调用系统调用
  2. 需要调用系统调用

2.4.1 不需要调用系统调用

不需要切换到内核空间即可完成函数的全部功能,并将结果反馈给应用程序,如strcpy,bzero等字符串操作函数

2.4.2 需要调用系统调用

需要切换到内核空间,这类函数通过封装系统调用去实现相应功能,如printf、fread等

2.4.3 库函数与系统调用的关系

并不是所有的系统调用都被封装成了库函数,系统的很多功能需要通过系统调用才能控制

image-20240222140533433

系统调用需要时间,程序中频繁使用系统调用会降低程序的运行效率。

当运行内核代码时,CPU工作在内核态,在系统调用发生前,需要保存用户态的栈和内存环境,然后转入内核态工作。

系统调用结束后,又要切换到用户态,这种环境的切换很消耗时间。

库函数的优势:设置不同类型的缓冲区,减少直接调用IO系统的次数,节省时间。大多数库函数的本质也是系统调用,只不过库函数有缓冲区,能够节省时间。

标签:02,文件,Shell,int,2024,描述符,调用,fd,include
From: https://www.cnblogs.com/hasaki-yasuo/p/18027213

相关文章

  • dp 学习笔记 (2024/2/22 - )
    计数[ARC107D]NumberofMultisets[ARC104D]MultisetMean大值域限制偏序计数[CF1295F]GoodContest[ARC104E]RandomLIS......
  • 【专题】2023年全球移动应用(非游戏)营销趋势白皮书报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=35180原文出处:拓端数据部落公众号随着国内政策调整,移动APP业务前景充满不确定性,但这也为出海应用带来了新机遇。2023年,AI和短剧应用的崛起为出海行业注入了信心。随着用户需求增长和技术进步,这两个领域有望在2024年迎来更大发展。阅读原文,获取专......
  • 2024初三集训模拟测试4
    2024初三集训模拟测试4\(T1\)打赌\(0pts\)\(T2\)舞会\(0pts\)\(T3\)最小生成树\(0pts\)经打表,有最小生成树的边权和为\(n-1\),构造每条边上的两端点互质即可。故\(\prod\limits_{i=1}^{n}\varphi(i)\)即为所求。点击查看代码constllp=100000007;llph......
  • 2024初三集训模拟测试4
    T1打赌简单题,模拟一下即可。T2舞会小贪心,尽量找离自己最近的防止后面的不能找。T3最小生成树显然权值和为\(n-1\),就是连互质的数,然后要求父亲小于儿子,所以欧拉函数一乘即可。T4买汽水正解是分成两组后搜索加剪枝,随机化也能过,数据很水。......
  • 墨天轮2023年度数据库获奖名单
    随着数字化转型深入推进和数据量的爆炸式增长,千行百业应用对数据库的需求变化推动数据库技术加速创新,全球数据库产业快速发展,我国已迈入第一梯队。2023年国产数据库在技术创新、市场竞争和国际合作等方面取得了显著的成就,展现出振奋人心的发展态势。墨天轮数据社区以近50个客观中......
  • 2024.02《高效学习法》
     背口诀、划重点、反复温习……各种方法都试过了,可为什么学习成绩还是没有提高呢?其实,你不是不会学习,而是不知道正确的学习方法!日本学习之神DaiGo公开自己独创并长年使用、科学有效、实践性极高的学习秘籍:想象自己把学习内容输出到10岁的孩子都能听懂、不写学习目标而写你掌......
  • 2023年总结
    2023年:1.工作在狗东,晋升T8级别。2.在技术架构团队,一直在一线。3.输出了5+个工具或者框架,交易团队多少都有在用,输出文档N篇,内网居多,再也没有用一周写一遍像样的文章了(比较忙)。4.大部分业余时间贡献给了中医(线上性能调优搞的有点麻木了,想冲击一下人类最高智慧,颇难,2023共看了......
  • AutoCAD2024画圆或矩形实时预览消失了如何解决?
    最近有小伙伴问这个问题,他在使用AutoCAD绘制图形时,发现画圆或矩形实时预览没有了,如下,画图不容易定位,非常影响画图效率,十分苦恼不知道如何恢复? 正常CAD画圆(或矩形)会显示实时预览,如下:操作步骤:AutoCAD20241、打开AutoCAD2024软件,然后在命令栏输入:DRAGMODE,然后按Enter键......
  • 我的2023
    今天是春节的最后一天,因为工作上临时有点事,很不情愿的打开电脑看着也就10天没看代码觉得非常陌生。之后便准备将迟迟未写的2023总结补完,这个传统从16年至今已经坚持将近7年时间了,今年当然也不能意外。健身今年要说最让我印象深刻的事就是健身了,为此我投入了大量的时间。......
  • 12.【2024初三集训模拟测试4】
    \(\Huge打了一场模拟赛,又垫底了。qwq\)2024初三集训模拟测试4\(\Huge还是垫底赛大佬。qwq\)赛时差点忘改\(freopen\),用的全是\(T1\)的文件,\(9:30\)才发现,吓\(④\)。T1打赌\(?pts\)又是\(\Huge\%\)你,打赌\(\Huge......