当前位置:   article > 正文

Linux下的系统编程——系统调用(五)_系统调用的语法格式是()。

系统调用的语法格式是()。

前言:

操作系统实现并提供给外部应用程序的编程接口。(Application Programming Interface,API)。系统调用就是应用程序同系统之间数据交互的桥梁。

一、open/close函数

1.open函数:

    (1)int open(char *pathname, int flags)    #include <unistd.h>

    参数:
        pathname: 欲打开的文件路径名

        flags:文件打开方式:  #include <fcntl.h>

                 O_RDONLY|O_WRONLY|O_RDWR                    O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK ....

    返回值:
        成功: 打开文件所得到对应的 文件描述符(整数)

        失败: -1, 设置errno    

  1. 语法
  2. open()方法语法格式如下:
  3. os.open(file, flags[, mode]);
  4. 参数
  5. file – 要打开的文件
  6. flags – 该参数可以是以下选项,多个使用 “|” 隔开:
  7. O_RDONLY: 以只读的方式打开
  8. O_WRONLY: 以只写的方式打开
  9. O_RDWR : 以读写的方式打开
  10. O_NONBLOCK: 打开时不阻塞
  11. O_APPEND: 以追加的方式打开
  12. O_CREAT: 创建并打开一个新文件
  13. O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)
  14. O_EXCL: 如果指定的文件存在,返回错误
  15. O_SHLOCK: 自动获取共享锁
  16. O_EXLOCK: 自动获取独立锁
  17. O_DIRECT: 消除或减少缓存效果
  18. O_FSYNC : 同步写入
  19. O_NOFOLLOW: 不追踪软链接
  20. 1)PROT_READ:表示内存段内的内容可写;
  21. 2)PROT_WRITE:表示内存段内的内容可读;
  22. 3)PROT_EXEC:表示内存段中的内容可执行;
  23. 4)PROT_NONE:表示内存段中的内容根本没法访问。

 

    (2)int open(char *pathname, int flags, mode_t mode)        123  775    

    参数:
        pathname: 欲打开的文件路径名

        flags:文件打开方式:    

                O_RDONLY|O_WRONLY|O_RDWR                    O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK ....

        mode: 参数3使用的前提, 参2指定了 O_CREAT。    

                取值8进制数,用来描述文件的 访问权限。 rwx    0664

                创建文件最终权限 = mode & ~umask

    返回值:
        成功: 打开文件所得到对应的 文件描述符(整数)

        失败: -1, 设置errno    

2.close函数:

    int close(int fd);

3.错误处理函数:        

    与 errno 相关。

        printf("xxx error: %d\n", errno);

 

 

    char *strerror(int errnum);

        printf("xxx error: %s\n", strerror(errno));

    void perror(const char *s);

        perror("open error");

二、read/write函数:

1.read函数:

    ssize_t read(int fd, void *buf, size_t count);

    参数:
        fd:      文件描述符

        buf:    存数据的缓冲区

        count:缓冲区大小

    返回值:

        0:          读到文件末尾。

        成功;    > 0 读到的字节数。

        失败:    -1, 设置 errno

        -1: 并且 errno = EAGIN 或 EWOULDBLOCK, 说明不是read失败,而是read在以非阻塞方式读一个设备文件(网络文件),并且文件无数据。

2.write函数:

    ssize_t write(int fd, const void *buf, size_t count);

    参数:
        fd:     文件描述符

        buf:   待写出数据的缓冲区

        count:数据大小

    返回值:

        成功;    写入的字节数。

        失败:    -1, 设置 errno

示例:

用read和write函数实现cp操作(将open.c文件中的代码复制到open2.c中)

  1. 1 #include <unistd.h>
  2. 2 #include <fcntl.h>
  3. 3 #include <stdlib.h>
  4. 4 #include <pthread.h>
  5. 5 #include <string.h>
  6. 6 #include <stdio.h>
  7. 7
  8. 8 int main(int argc,char *argv[])
  9. 9 {
  10. 10 char buf[1024];
  11. 11
  12. 12 int n = 0;
  13. 13
  14. 14 int fd1 = open(argv[1],O_RDONLY); //read
  15. 15 if(fd1 == -1){
  16. 16 perror("open argv1 error");
  17. 17 exit(1);
  18. 18 }
  19. 19
  20. 20 int fd2 = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);
  21. 21 if(fd2 == -1){
  22. 22 perror("open argv2 error");
  23. 23 exit(1);
  24. 24 }
  25. 25 while((n = read(fd1,buf,1024))!=0){
  26. 26 if(n < 0)
  27. 27 {
  28. 28 perror("read error");
  29. 29 break;
  30. 30 }
  31. 31 write(fd2,buf,n);
  32. 32 }
  33. 33
  34. 34 close(fd1);
  35. 35 close(fd2);
  36. 36 }
  37. ~

系统调用和库函数比较

预读入缓输出

三、阻塞、非阻塞

    阻塞、非阻塞:  是设备文件、网络文件的属性。

    产生阻塞的场景: 读设备文件、读网络文件。(读常规文件无阻塞概念。)

    /dev/tty --> 终端文件。

1.阻塞

  1. 1 #include <unistd.h>
  2. 2 #include <stdlib.h>
  3. 3 #include <stdio.h>
  4. 4
  5. 5
  6. 6 int main(void)
  7. 7 {
  8. 8 char buf[10];
  9. 9 int n;
  10. 10
  11. 11 n = read(STDIN_FILENO, buf, 10);
  12. 12 // #define STDIN_FILENO 0 STDOUT_FILENO 1 STDERR_FILENO 2
  13. 13 if(n < 0){
  14. 14 perror("read STDIN_FILENO");
  15. 15 exit(1);
  16. 16 }
  17. 17 write(STDOUT_FILENO, buf, n);
  18. 18
  19. 19 return 0;
  20. 20 }

 现在发生阻塞,一直处于读的状态

当我们输入一串字符时,读操作结束,阻塞解除

那么阻塞是谁的特性?是read/write的吗?

答案当然不是了,应该是文件的属性,也就是设备文件或者网络文件

2.改变阻塞特性

 open("/dev/tty", O_ RDWR|O_NONBLOCK)    --- 设置 /dev/tty 非阻塞状态。(默认为阻塞状态)

3.非阻塞

  1. 1 #include <unistd.h>
  2. 2 #include <fcntl.h>
  3. 3 #include <errno.h>
  4. 4 #include <stdio.h>
  5. 5 #include <stdlib.h>
  6. 6 #include <string.h>
  7. 7
  8. 8 int main(void)
  9. 9 {
  10. 10 char buf[10];
  11. 11 int fd, n;
  12. 12
  13. 13 fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
  14. 14 if (fd < 0) {
  15. 15 perror("open /dev/tty");
  16. 16 exit(1);
  17. 17 }
  18. 18
  19. 19 tryagain:
  20. 20
  21. 21 n = read(fd, buf, 10);
  22. 22 if (n < 0) {
  23. 23 if (errno != EAGAIN) { // if(errno != EWOULDBLOCK)
  24. 24 perror("read /dev/tty");
  25. 25 exit(1);
  26. 26 } else {
  27. 27 write(STDOUT_FILENO, "try again\n", strlen("try again\n"));
  28. 28 sleep(2);
  29. 29 goto tryagain;
  30. 30 }
  31. 31 }
  32. 32
  33. 33 write(STDOUT_FILENO, buf, n);
  34. 34 close(fd);
  35. 35
  36. 36 return 0;
  37. 37 }

 4.设置非阻塞后的循环停止时间

  1. 1 #include <unistd.h>
  2. 2 #include <fcntl.h>
  3. 3 #include <stdlib.h>
  4. 4 #include <stdio.h>
  5. 5 #include <errno.h>
  6. 6 #include <string.h>
  7. 7
  8. 8 #define MSG_TRY "try again\n"
  9. 9 #define MSG_TIMEOUT "time out\n"
  10. 10
  11. 11 int main(void)
  12. 12 {
  13. 13 char buf[10];
  14. 14 int fd, n, i;
  15. 15
  16. 16 fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
  17. 17 if(fd < 0){
  18. 18 perror("open /dev/tty");
  19. 19 exit(1);
  20. 20 }
  21. 21 printf("open /dev/tty ok... %d\n", fd);
  22. 22
  23. 23 for (i = 0; i < 5; i++){
  24. 24 n = read(fd, buf, 10);
  25. 25 if (n > 0) { //说明读到了东西
  26. 26 break;
  27. 27 }
  28. 28 if (errno != EAGAIN) { //EWOULDBLOCK
  29. 29 perror("read /dev/tty");
  30. 30 exit(1);
  31. 31 } else {
  32. 32 write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
  33. 33 sleep(2);
  34. 34 }
  35. 35 }
  36. 36
  37. 37 if (i == 5) {
  38. 38 write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));
  39. 39 } else {
  40. 40 write(STDOUT_FILENO, buf, n);
  41. 41 }
  42. 42
  43. 43 close(fd);
  44. 44
  45. 45 return 0;
  46. 46 }

四、文件描述符:

     PCB进程控制块: 本质是结构体

    成员:文件描述符表

    文件描述符:0/1/2/3/4........../1023     表中可用的最小的。

    0 - STDIN_FILENO

    1 - STDOUT_FILENO

    2 - STDERR_FILENO

五、fcntl函数:

         改变一个【己经打开】的文件的访问控制属性。

        重点掌握两个参数的使用,F_GETFL 和 F_SETFL。
        【fcntl.c】

     int (int fd, int cmd, ...)

    int flgs = fcntl(fd,  F_GETFL);

    flgs |= O_NONBLOCK

    fcntl(fd,  F_SETFL, flgs);

    获取文件状态: F_GETFL

    设置文件状态: F_SETFL

  1. 1 #include <unistd.h>
  2. 2 #include <fcntl.h>
  3. 3 #include <errno.h>
  4. 4 #include <stdio.h>
  5. 5 #include <stdlib.h>
  6. 6 #include <string.h>
  7. 7
  8. 8 #define MSG_TRY "try again\n"
  9. 9
  10. 10 int main(void)
  11. 11 {
  12. 12 char buf[10];
  13. 13 int flags, n;
  14. 14
  15. 15 flags = fcntl(STDIN_FILENO, F_GETFL); //获取stdin属性信息
  16. 16 if(flags == -1){
  17. 17 perror("fcntl error");
  18. 18 exit(1);
  19. 19 }
  20. 20 flags |= O_NONBLOCK;
  21. 21 int ret = fcntl(STDIN_FILENO, F_SETFL, flags);
  22. 22 if(ret == -1){
  23. 23 perror("fcntl error");
  24. 24 exit(1);
  25. 25 }
  26. 26
  27. 27 tryagain:
  28. 28 n = read(STDIN_FILENO, buf, 10);
  29. 29 if(n < 0){
  30. 30 if(errno != EAGAIN){
  31. 31 perror("read /dev/tty");
  32. 32 exit(1);
  33. 33 }
  34. 34 sleep(3);
  35. 35 write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
  36. 36 goto tryagain;
  37. 37 }
  38. 38 write(STDOUT_FILENO, buf, n);
  39. 39
  40. 40 return 0;
  41. 41 }

 六、lseek函数:

lseek函数:

    off_t lseek(int fd, off_t offset, int whence);

    参数:
        fd:         文件描述符

        offset:   偏移量

        whence:起始偏移位置: SEEK_SET/SEEK_CUR/SEEK_END

    返回值:

        成功:较起始位置偏移量

        失败:-1 errno

    应用场景:    
        1. 文件的“读”、“写”使用同一偏移位置

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. int main(void)
  7. {
  8. int fd, n;
  9. char msg[] = "It's a test for lseek\n";
  10. char ch;
  11. fd = open("lseek.txt", O_RDWR|O_CREAT, 0644);
  12. if(fd < 0){
  13. perror("open lseek.txt error");
  14. exit(1);
  15. }
  16. write(fd, msg, strlen(msg));
  17. //使用fd对打开的文件进行写操作,问价读写位置位于文件结尾处。
  18. lseek(fd, 0, SEEK_SET);
  19. //修改文件读写指针位置,位于文件开头。 注释该行会怎样呢?
  20. while((n = read(fd, &ch, 1))){
  21. if(n < 0){
  22. perror("read error");
  23. exit(1);
  24. }
  25. write(STDOUT_FILENO, &ch, n);
  26. //将文件内容按字节读出,写出到屏幕
  27. }
  28. close(fd);
  29. return 0;
  30. }

 2. 使用lseek获取文件大小

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. int main(int argc,char *argv[])
  7. {
  8. int fd;
  9. fd = open(argv[1],O_RDWR);
  10. if(fd < -1){
  11. perror("open lseek.txt error");
  12. exit(1);
  13. }
  14. int len = lseek(fd, 0, SEEK_END);
  15. if(len == -1){
  16. perror("lseek error");
  17. exit(1);
  18. }
  19. printf("len of msg = %d\n", len);
  20. close(fd);
  21. return 0;
  22. }

 

3. 使用lseek拓展文件大小:要想使文件大小真正拓展,必须引起IO操作。

    使用 truncate 函数,直接拓展文件。    int ret = truncate("dict.cp", 250);

(1)扩展文件大小:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. int main(int argc,char *argv[])
  7. {
  8. int fd;
  9. fd = open(argv[1],O_RDWR);
  10. if(fd < -1){
  11. perror("open lseek.txt error");
  12. exit(1);
  13. }
  14. int len = lseek(fd, 111, SEEK_END);
  15. if(len == -1){
  16. perror("lseek error");
  17. exit(1);
  18. }
  19. printf("len of msg = %d\n", len);
  20. close(fd);
  21. return 0;
  22. }

 (2)扩展文件大小—引起IO操作:

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <fcntl.h>
  5. int main(void)
  6. {
  7. int fd;
  8. char buf[64];
  9. int ret = 0;
  10. fd = open("./file.txt", O_RDONLY);
  11. if (fd == -1) {
  12. printf("open file error\n");
  13. exit(1);
  14. }
  15. printf("---open ok---\n");
  16. while((ret = read(fd, buf, sizeof(buf)))) {
  17. write(1, buf, ret);
  18. }
  19. close(fd);
  20. return 0;
  21. }

 使用 truncate 函数,直接拓展文件

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. int main(int argc,char *argv[])
  7. {
  8. int ret = truncate("test.c",250);
  9. printf("ret = %d\n",ret);
  10. return 0;
  11. }

七、传入传出参数:

1.传入参数:

    1. 指针作为函数参数。

    2. 通常有const关键字修饰。

    3. 指针指向有效区域, 在函数内部做读操作。

2.传出参数:

    1. 指针作为函数参数。

    2. 在函数调用之前,指针指向的空间可以无意义,但必须有效。

    3. 在函数内部,做写操作。

    4。函数调用结束后,充当函数返回值。

3.传入传出参数:

    1. 指针作为函数参数。

    2. 在函数调用之前,指针指向的空间有实际意义。

    3. 在函数内部,先做读操作,后做写操作。

    4. 函数调用结束后,充当函数返回值。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/278462?site
推荐阅读
相关标签
  

闽ICP备14008679号