• 【Linux】进程间通信


    目录

    匿名管道:

    代码演示: 

    管道的特性: 

    验证部分特性: 

    管道大小

    命名管道:

    命令行代码实验:

    命名管道实现的相关代码:

    Client端:

    server端:

    makefile:

    运行结果:


    进程间通信的本质:让不同的进程,能看到同一份系统资源(系统通过某种方式提供的系统内存)

    管道通信

    匿名管道 and 命名管道:底层的原理是基本一样的

    匿名管道:

    供具有血缘关系的进程,进行进程间通信(保证不同的进程,看到同一份资源)(常见于父子)

     

    父子进程关闭不需要的文件描述符,来达到构建单向通信的信道的目的

    这里有2个问题:

    为什么需要关,那么曾经为什么要打开呢?

    如果不打开读写,子进程拿到的文件打开方式必定和父进程一样,无法通信,同时更加灵活!

    为什么要关闭?

    一方面证明管道单向通信的特性,主要为了防止误操作

    int pipe(int pipefd[2])  

    输出型参数,通过调用pipe,拿到刚刚打开的管道文件的描述符

    2个fd,对应于一个读,一个写

    代码演示: 

    1. #include
    2. 2 #include
    3. 3 #include
    4. 4 #include
    5. 5 #include
    6. 6 int main()
    7. 7 {
    8. 8 int pipe_fd[2] = {0};
    9. 9 if(pipe(pipe_fd) < 0)
    10. 10 {
    11. 11 perror("pipe");
    12. 12 return 1;
    13. 13 }
    14. 14
    15. 15 printf("%d,%d\n",pipe_fd[0],pipe_fd[1]);
    16. 16
    17. 17 pid_t id = fork();
    18. 18 if(id < 0)
    19. 19 {
    20. 20 perror("fork");
    21. 21 return 2;
    22. 22 }
    23. 23 else if(id==0)
    24. 24 {
    25. 25 //child让子进程进行写入
    26. 26 close(pipe_fd[0]);
    27. 27
    28. 28
    29. 29 const char*msg = "我是子进程\n";
    30. 30 int count = 5;
    31. 31 while(count)
    32. 32 {
    33. 33 write(pipe_fd[1],msg,strlen(msg));//向管道当中写入的功能
    34. 34 sleep(1);
    35. 35 count--;
    36. 36 }
    37. 37 close(pipe_fd[1]);
    38. 38 exit(0);
    39. 39 }
    40. 40 else{
    41. 41 //child让父进行读取
    42. 42 close(pipe_fd[1]);
    43. 43 char buffer[64];
    44. 44 while(1)
    45. 45 {
    46. 46 buffer[0] = 0;
    47. 47 ssize_t size = read(pipe_fd[0],buffer,sizeof(buffer)-1);//管道中读取
    48. 48 if(size > 0)
    49. 49 {
    50. 50 buffer[size] = 0;
    51. 51 printf("从子进程中来的:%s\n",buffer);
    52. 52 }
    53. 53 else if(size == 0)
    54. 54 {
    55. 55 printf("管道文件关闭,子进程退出\n");
    56. 56 break;
    57. 57 }
    58. 58 else{
    59. 59 break;
    60. 60 }
    61. 61 }
    62. 62 int status = 0;
    63. 63 if(waitpid(id,&status,0)>0)
    64. 64 {
    65. 65 printf("子进程退出,等待成功\n");
    66. 66 }
    67. 67 close(pipe_fd[0]);
    68. 68 }
    69. 69 return 0;
    70. 70 }

    管道的特性: 

    如果管道里面已经没有消息,父进程(读端)在干什么?

    等待,在等管道内部有数据就绪

    如果管道里面写端已经写满了,继续写入,还能写吗?

    不能,等待管道内部有空闲空间(等父进程读走)

    第一:管道自带同步机制

    第二:管道是单向通信的

    第三:管道是面向字节流的

    第四:管道只能保证具有血缘关系的进程通信,常用于父子

    第五:管道可以保证一定程度的数据读取的原子性

    第六:进程退出,曾经打开的文件也会被关掉,管道也是文件,所以管道的生命周期随进程

    验证部分特性: 

    read端write端结果
    不读write阻塞
    不写read阻塞
    不写 & 关闭read读取到0,文件结束!
    不读 & 关闭write被OS发送的SIGPIPE杀掉

    读取关闭,一直在写

    毫无意义,一直在写,本质就是在浪费系统资源,写进程会立马被OS终止掉!(通过发送信号终止子进程)

    管道大小

    64KB(非原子性写入管道当中的单元大小)

    4KB(原子性写入的)

    命名管道:

    理解命名管道的原理

    1:先保证两个进程能看到同一份资源

    普通文件,是需要将数据刷新到磁盘的,持久化存储

    命令行代码实验:

    命名管道实现的相关代码:

    Client端:

    1. #include
    2. 2 #include
    3. 3 #include
    4. 4 #include
    5. 5 #include
    6. 6 #include
    7. 7
    8. 8 #define FIFO "./fifo"
    9. 9 int main()
    10. 10 {
    11. 11 int fd = open(FIFO,O_WRONLY);
    12. 12 if(fd < 0)
    13. 13 {
    14. 14 perror("open");
    15. 15 return 2;
    16. 16 }
    17. 17 char buffer[128];
    18. 18 while(1)
    19. 19 {
    20. 20 printf("Please Enter");
    21. 21 fflush(stdout);
    22. 22 buffer[0] = 0;
    23. 23 ssize_t s = read(0,buffer,sizeof(buffer));//从标准输入里读数据
    24. 24 if(s > 0)
    25. 25 {
    26. 26 buffer[s] = 0;
    27. 27 write(fd,buffer,strlen(buffer));//写到管道文件
    28. 28 }
    29. 29 else if(s == 0)
    30. 30 {
    31. 31 printf("client quit\n");
    32. 32 break;
    33. 33 }
    34. 34 else{
    35. 35 break;
    36. 36 }
    37. 37 }
    38. 38 close(fd);
    39. 39 return 0;
    40. 40 }

    server端:

    1. #include
    2. 2 #include
    3. 3 #include
    4. 4 #include
    5. 5 #include
    6. 6
    7. 7 #define FIFO "./fifo"
    8. 8 int main()
    9. 9 {
    10. 10 int ret = mkfifo(FIFO,0644);
    11. 11 if(ret < 0)
    12. 12 {
    13. 13 perror("mkfifo");
    14. 14 return 1;
    15. 15 }
    16. 16 int fd = open(FIFO,O_RDONLY);
    17. 17 if(fd < 0)
    18. 18 {
    19. 19 perror("open");
    20. 20 return 2;
    21. 21 }
    22. 22 char buffer[128];
    23. 23 while(1)
    24. 24 {
    25. 25 buffer[0] = 0;
    26. 26 ssize_t s = read(fd,buffer,sizeof(buffer));
    27. 27 if(s > 0)
    28. 28 {
    29. 29 buffer[s] = 0;
    30. 30 printf("client : %s\n",buffer);
    31. 31 }
    32. 32 else if(s == 0)
    33. 33 {
    34. 34 printf("client quit\n");
    35. 35 break;
    36. 36 }
    37. 37 else{
    38. 38 break;
    39. 39 }
    40. 40 }
    41. 41 close(fd);
    42. 42 return 0;
    43. 43 }
    44. ~

    makefile:

    1. client:client.c
    2. 5 gcc -o $@ $^
    3. 6 server:ser.c
    4. 7 gcc -o $@ $^
    5. 8 .PHONY:clean
    6. 9 clean:
    7. 10 rm -f client ser fifo

    运行结果:

  • 相关阅读:
    压缩包里的文件名可以这样隐藏起来
    12.88万的小魔驼2.0量产交付,末端物流自动配送从概念走向现实
    Fastadmin 子级菜单展开合并,分类父级归纳
    【Linux修炼手册:基本指令(下)】
    【机器学习笔记13】softmax多分类模型【上篇】完整流程与详细公式推导
    pycharm虚拟环境安装指定python版本/ python3.8 / 从python3.9降级到3.8
    软件测试面试题 —— 整理与解析(5)
    软件工程-第7章 面向对象方法基础
    如何针对结构化文本查询修改记录
    Day09--全局事件共享-在页面中使用store中的成员
  • 原文地址:https://blog.csdn.net/weixin_47132900/article/details/126548981