Linux_2 管道(任务间的通信)
目录
1. 认识无名管道
2. 无名管道大小测试
3. 无名管道练习
4. 无名管道_两个管道双向传输
5. 有名(命名)管道
总结
任务间的通信与同步(7种)
管道 信号 信号量 互斥锁 消息队列 共享内存 socket套接字
1. 认识无名管道
管道相关的关键概念
管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
(1)管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
(2)只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
(3)单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
(4)数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
管道的创建:
#include <unistd.h>
int pipe(int fd[2])//Return 0 on success,or -1 on error
该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。
管道的读写规则:
管道两端可分别用描述字 fd[0] 以及 fd[1] 来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字 fd[0] 表示,称其为管道读端;另一端则只能用于写,由描述字fd[1] 来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。 一般文件的I/O函数都可以用于管道,如close、read、write等等。
从管道中读取数据:
(1)如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;
(2)当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。
注:(PIPE_BUF在 include/linux/limits.h 中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF至少为 512字节,red hat 7.2中为4096)。
向管道中写入数据:
(1)向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。
(2)管道中的读端关闭,此时向管道写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。
当管道中父进程没有写入数据时,而子进程使用read读管道中的数据时,read将一直阻塞,等待管道中写入数据
NAME : pipe , pipe2 ----- creat pipe
pip1.c
/*parent process : write pipechild process : read pipe
*/
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>int main(void)
{int fd[2];int pid;if(pipe(fd) == -1) //创建管道,创建错误返回-1,正确返回0perror("pipe");pid = fork(); // 创建进程if(pid > 0) // 父进程 fd[0] 读 fd[1] 写{close(fd[0]); //关闭管道读端sleep(5);write(fd[1], "ab", 2); //写管道写数据(2为写入字符为两个字节大小)while(1);}else if(pid == 0) // 子进程复制了管道{ char ch[2]; // 用于接收数据printf("child process is waiting for data: \n");close(fd[1]); // 关闭管道写端read(fd[0], ch, 2); // 存放到ch,2个字节大小printf("read from pipe: %s\n", ch);} return 0;
}
读函数read
ssize_t read ( int fd, void * buf, size_t nbyte)
read函数是负责从fd中读取内容. 成功时,read返回实际所读的字节数,如果返回的值是0,表示已经读到文件的结束了.
小于0表示出现了错误. 如果错误为EINTR说明读是由中断引起的, 如果是ECONNREST表示网络连接出了问题.
写函数write
ssize_t write ( int fd, const void * buf, size_t nbytes)
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能.
1)write的返回值大于0,表示写了部分或者是全部的数据.
2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理. 如果错误为EINTR表示在写的时候出现了中断错误.
如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接).
2. 无名管道大小测试
管道的容量是有限的:管道的存储能力为65536字节
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/wait.h>int main(void)
{pid_t pid;int fd[2];if(pipe(fd) == -1)perror("pipe");pid = fork(); // 创建子进程if(pid == 0) // child process : write to the pipe{ // 子进程不断写入管道*char ch = '*';int n = 0;close(fd[0]); // 关闭读端while(1){ // 地址write(fd[1], &ch, 1);printf("count = %d\n", ++n);}} else if(pid > 0) //parent process : wait until child process is over{waitpid(pid, NULL, 0); // 父进程等待子进程结束}
}
结果:。。。count = 65536 (字节)
3. 无名管道练习
子进程把键盘输入的数据写入管道,父进程读取数据
pip_w&r_.c
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/wait.h>int main(void)
{pid_t pid;int fd[2];if(pipe(fd) == -1)perror("pipe");pid = fork(); //创建子进程if(pid == 0) //child process : write to the pipe{ char tmp[100]; // 用于存储数据close(fd[0]);while(1){printf("parent processs is waiting for you message\n");scanf("%s", tmp) // 等待键盘输入数据write(fd[1], tmp, sizeof(tmp)); // 将数据写入管道 }} else if(pid > 0) //parent process : 读取子进程的输入{char tmp[100];close(fd[1]);while(1) // 只要管道有内容就会读取{read(fd[0], tmp, sizeof(tmp)); //读取printf("read from pipe : %s\n", tmp); // 输出}}
}
4. 无名管道_两个管道双向传输
two_pip.c
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>
int main(void)
{pid_t pid;int fd[2];int fd2[2]; // 两个描述符// 判断是否成功if(pipe(fd) == -1)perror("pipe");if(pipe(fd2) == -1)perror("pipe");pid = fork(); //创建子进程if(pid == 0) //child process :{ char tmp[100];close(fd[1]); //关闭fd管道的写 close(fd2[0]); //关闭fd管道的读while(1){memset(tmp, '\0', sizeof(tmp)); // 对tmp做清空处理read(fd[0], tmp, sizeof(tmp)); // 子进程等待去读管道for( i = 0; i < sizeof(tmp); i++) // 有数据时,read由阻塞变为非阻塞tmp[i] = toupper(tmp[i]); // 将所有的字符变为大写toupperwrite(fd2[1], tmp, sizeof(tmp)); // 写入管道fd2}} else if(pid > 0) //parent process : 读取子进程的输入{char tmp[100];close(fd[0]);close(fd[1]);while(1){ memset(tmp, '\0', sizeof(tmp));gets(tmp); //父进程由键盘输出write(fd[1], tmp, sizeof(tmp)); //向子进程写入小写memset(tmp, '\0', sizeof(tmp));read(fd2[0], tmp, sizeof(tmp)); //读取子进程传过来的大写printf("after change : %s \n", tmp)}}
}
memset 函数
代码示例
#include <stdio.h>
#include <string.h>int main ()
{char str[50];strcpy(str,"This is string.h library function");puts(str);memset(str,'$',7);puts(str);return(0);
}// This is string.h library function
// $$$$$$$ string.h library function
5. 有名(命名)管道
- 匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIFO),也叫命名管道、FIFO 文件。
- 有名管道(FIFO)不同于匿名管道之处在于它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据。
- 一旦打开了 FIFO,就能在它上面使用与操作匿名管道和其他文件的系统调用一样的 I/O 系统调用了(如read()、write() 和 close())。与管道一样,FIFO 也有一个写入端和读取端,并且从管道中读取数据的顺序与写入的顺序是一样的。FIFO 的名称也由此而来:先入先出。
- 有名管道(FIFO) 和匿名管道(pipe)有一些特点是相同的,不一样的地方在于:
1. FIFO 在文件系统中作为一个特殊文件存在,但 FIFO 中的内容却存放在内存中。
2. 当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。
3. FIFO 有名字,不相关的进程可以通过打开有名管道进行通信。
非亲缘关系进程之间进行管道通信
NAME : mkfifo , mkfifoat - make a FIFO(先入先出) special file(a named pipe)
模式(model):写权限4,读权限2,可执行权限1 (主要读写)
函数功能:创建一个FIFO文件,用于进程之间的通信。pathname就是路径名,mode是该文件的权限。返回值表示是否成功,返回0表示成功,返回-1表示失败,失败原因在errno中。(建立FIFO的时候,要求不存在这样的FIFO)。
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);// 函数功能:创建一个FIFO文件,用于进程之间的通信。pathname就是路径名,mode是该文件的权限。返回值表示是否成功,返回0表示成功,返回-1表示失败,失败原因在errno中。(建立FIFO的时候,要求不存在这样的FIFO)。
read_named_pipe.c
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>int main(void)
{int ret;int fd;char buf[100];ret = mkfifo("my_fifo", 666); // 创建文件,权限if(ret != 0)perror("mkfifo");printf("prepare reading from the pip :\n");fd = open("my_fifo", 0_RDWR);if(fd == -1)perror("open");while(1){memset(buf, '\0', sizeof(buf));read(fd, buf, sizeof(buf));printf("read from named pipe : %s\n", buf);sleep(1);}return 0; }
编译 :gcc read_named_pipe.c -o read
重新开一个终端:
write_named_pipe.c
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;char buf[100];fd = open("my_fifo", 0_WRONLY);if(fd == -1)perror("open");if(argc == 1){printf("please send something to the named pipe :\n");exit(EXIT_FAILURE);}strcpy(buf, argv[1]);write(fd, buf, sizeof(buf));printf("write to the pipe : %s\n", buf);return 0; }
编译:gcc write_named_pipe.c -o write
./write hello morning
总结
有名管道 (可以在任意两个进程之间通信)
无名管道(只能在父子进程之间进行通信)(有一个读端和一个写端,缺一不可)
管道写端关闭,则读端返回值为0;
管道读端关闭,则写端会产生异常(会收到信号SIGPIPE)
管道为空, 那么读会阻塞
管道写满, 那么写会阻塞
1.有名管道和无名管道的区别:有名管道可以在任意两个进程之间通信;无名管道只能在父子进程之间进行通信
2.写入管道的数据在哪里? 在内存中(不是在磁盘上)
3.管道的通信方式: 半双工(数据可以从a到b,也可以从b到a,但是某一时刻只能选择其中一个)
Linux_2 管道(任务间的通信)相关推荐
- 【操作系统】进程间的通信——管道
进程间的通信-管道 管道 进程间的通信(IPC-Inter-Process Communication)有多种方式,管道是其中最基本的方式. 管道是半双工的,即是单向的. 管道是FIFO(先进先出)的 ...
- 进程间的通信IPC(无名管道和命名管道)
进程间的通信IPC介绍 进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息. IPC的方式通常有管道(包括无名管道和命名管道).消息队列.信号量 ...
- 进程间的通信——无名管道
进程间的通信--无名管道 宗旨:技术的学习是有限的,分享的精神是无限的. 一.进程间的通信 (1)同主机进程间数据交互机制:无名管道(PIPE),有名管道(FIFO).消息队列和共享内存.无名管道多用 ...
- 网络编程之 进程间的通信之管道的使用
如何使用管道是进程间通信的关键 博主先声明一下,关于处理进程创建以及销毁的方法. "子进程究竟何时终止????调用waitpid函数后还要无休止的等待子进程终止吗???&quo ...
- 命名管道(FIFO) Linux进程进程间的通信之命名管道(FIFO)
Linux进程进程间的通信之命名管道(FIFO) 命名管道(FIFO),它和一般的管道一样.都是作为中间的邮递员来实现两个进程间的通信交流. 命名管道(FIFO)有几个特点: 1.命名管道(FIFO) ...
- 2022.8.31 进程中无名管道的特点,无名管道的创建,为何无名管道只能能够实现具有亲缘关系的进程间的通信,以及实现利用无名管道父进程给子进程发送消息的完整代码。
无名管道通信 无名管道特点: (1):只能用于具有亲缘关系的进程之间的通信.(父子进程或兄弟进程) (2):是一个半双工的通信模式,具有固定的读端和写端.(fd[0]固定为读端,fd[1]固定为写端) ...
- 高并发编程-线程通信_使用wait和notify进行线程间的通信
文章目录 概述 场景 引子 synchronized wait/notify机制 synchronized wait/notify 改造 问题 概述 Java中线程通信协作的最常见的两种方式: syn ...
- Linux系统编程(三)进程间的通信
Linux系统编程(三)进程间的通信 一.为什么需要进程之间的通信(IPC)? 二.管道 1.概念 2.特质 3.原理 4.局限性 5.代码 2.读入数据 三.共享存储映射 注意事项 父子进程通信 一 ...
- 进程间的通信之1-----管道
进程间的通信之1-----管道 1.标准流管道 像文件操作有标准 io 流一样, 管道也支持文件流模式. 用来创建连接到另一进程的管道, 是通过函数 popen 和 pclose. 函数原型: #in ...
最新文章
- Ios文件连接dlna服务器,iOS播放多种视频格式,实现DLNA|AirPlay投射盒子总结
- python映射类型包括哪三种_python新手入门必备——映射类型相关函数
- flex 文字竖排_flex button字竖排展示
- ANSI,ASCII,Unicode的区别与联系!
- python输出数字方阵_在python里输出数字方阵
- 雨中的蚊子为啥不会被雨滴砸死?
- Tomcat7.0+的JNDI问题
- 学生成绩管理 php,php学生成绩管理系统(模板)
- [CSS] 详细解释 @media 属性与 (max-width:) and (min-width) 之间的关系及用法
- 暮光之城3蓝光BD高清下载
- 上海商业车险进平台验收通过
- 【商业】梳理你的商业模式
- D. Dirty Deeds Done Dirt Cheap
- 如何用ftp上传到服务器视频文件,ftp如何将文件上传到服务器上
- fiddler进行弱网测试
- 超时任务总结(tradingTask)
- matlab生成sinc函数,【 MATLAB 】sinc 函数简介
- MySql 循环执行语句,循环执行update,详细介绍【游标嵌套】
- 光纤收发器的6个指示灯说明
- 计算机如何永久删除文件无法找回,电脑文件永久性删除了怎么办?简单五招教你恢复...
热门文章
- 2013年10月高等教育国际金融全国统一命题考试
- IP地址和子网掩码的关系, 如何计算网络地址?
- easyExcel导出excel
- mipsel_24kc的linux内核,选择内核为4.14.195时的编译错误
- 基于Matlab模板匹配方法的车牌识别系统设计
- 定积分的计算(牛顿-莱布尼茨公式)
- 2020NYIST个人积分赛第五场-I
- frp使用反向代理实现https协议
- Linux 时间同步systemd-timesyncd介绍
- 教师计算机教程,中学化学教师计算机教学应用教程——中小学教师计算机教学应用教程...