网站优化提升排名,优秀网站设计赏析怎么写,wordpress页面如何显示分类,电子商务网站建设的开发背景目录 一、Linux平台通信方式发展史二、进程间通信方式⭐⭐⭐三、无名管道3.1 特点⭐⭐⭐3.2 函数pipe3.3 注意事项⭐⭐⭐3.4 练习 四、有名管道4.1 特点⭐⭐⭐4.2 函数 mkfifo4.3 注意事项⭐⭐4.4 练习 五、无名管道与有名管道对比⭐⭐ 复杂的编程环境通常使用多个相关的进程来… 目录 一、Linux平台通信方式发展史二、进程间通信方式⭐⭐⭐三、无名管道3.1 特点⭐⭐⭐3.2 函数pipe3.3 注意事项⭐⭐⭐3.4 练习 四、有名管道4.1 特点⭐⭐⭐4.2 函数 mkfifo4.3 注意事项⭐⭐4.4 练习 五、无名管道与有名管道对比⭐⭐ 复杂的编程环境通常使用多个相关的进程来执行有关操作。进程之间必须进行通信来共享资源和信息。因此要求内核提供必要的机制这些机制通常称为进程间通信InterProcess Communication, IPC。 一、Linux平台通信方式发展史
早期通信方式早期的Unix IPC包括管道、FIFO和信号ATT的贝尔实验室对Unix早期的进程间通信进行了改进和扩充形成了“system V IPC”,其通信进程主要局限在单个计算机内。BSD加州大学伯克利分校的伯克利软件发布中心跳过了只能在同一计算机通信的限制形成了基于套接字socket的进程间通信机制。
二、进程间通信方式⭐⭐⭐
早期通信无名管道pipe有名管道fifo、信号semsystem V IPC共享内存(share memory) 、信号灯集semaphore、消息队列message queueBSD套接字socket
三、无名管道
3.1 特点⭐⭐⭐
只能用于具有亲缘关系的进程间进行通信半双工通信具有固定的读端与写端 单工只能单方面传输信息-广播 半双工可以双向但是同一时间只能一个方向传输信息 全双工可以双向同时传输信息无名管道可以看作一种特殊的文件对它的读写采用文件IOread、write管道是基于文件描述符通信方式。当一个无名管道创建会自动创建两个文件描述符分别的fd[0]、fd[1]其中fd[0]固定的读端fd[1]固定的写端
3.2 函数pipe
int pipe(int fd[2])
功能创建无名管道参数文件描述符fd[0]读端 fd[1]:写端返回值成功 0失败 -1 注管道要用文件I/O进行操作read,write,close且管道创建后fd[0]3,fd[1]4 例
3.3 注意事项⭐⭐⭐
当管道中无数据时读操作会阻塞管道中无数据将写端关闭读操作会立即返回管道中装满管道大小64K数据写阻塞一旦有4k空间写继续直到写满为止只有在管道的读端存在时向管道中写入数据才有意义。否则会导致管道破裂向管道中写入数据的进程将收到内核传来的SIGPIPE信号 (通常Broken pipe错误)。GDB调试可以查看到
代码示例
#include stdio.h
#include unistd.h
#include string.hint main(int argc, char const *argv[])
{int fd[2] {0};if (pipe(fd) 0){perror(pipe error);return -1;}printf(fd[0]:%d fd[1]:%d\n, fd[0], fd[1]);char buf1[32] {hello world!};char buf2[32] {0};// write(fd[1],buf1,strlen(buf1)); //往管道写入buf1// ssize_t s read(fd[0],buf2,32); //从管道读取数据到buf2// printf(%s %d\n,buf2,s);// close(fd[0]);// close(fd[1]);
#if 0// 1.管道中无数据读阻塞read(fd[0], buf2, 32);
#endif
#if 0// 2.将写端关闭读操作会立即返回close(fd[1]);read(fd[0],buf2,32);
#endif
#if 1//3.1 当无名管道中写满数据64k写阻塞char buf[65536] {0};write(fd[1], buf, 65536);printf(full\n);write(fd[1], a, 1);printf(write a ok\n);//至少读出4k的空间才能继续写read(fd[0], buf, 4095);write(fd[1], a, 1);printf(write a ok\n);
#endif
#if 1// 3.1 将读端关闭继续写close(fd[0]);write(fd[1], a, 1);printf(ok...\n);
#endif// close(fd[0]);// close(fd[1]);return 0;
}第三种情况管道破裂通过GDB调试查看到的结果如下
3.4 练习
父子进程实现通信父进程循环从终端输入数据子进程循环打印数据输入一次打印一次当输入quit结束使用无名管道
/*练习父子进程实现通信父进程循环从终端输入数据子进程循环打印数据当输入quit结束使用无名管道
*/
#include stdio.h
#include string.h
#include unistd.h
#include stdlib.h
#include sys/types.h
#include sys/wait.hint main(int argc, char const *argv[])
{char buf[32] {0};int fd[2] {0};if(pipe(fd)0) //创建无名管道{perror(pipe err);return -1;}pid_t pid fork();if(pid 0){perror(fork err);return -1;}else if(pid 0){while (1) //子进程循环从管道读取数据管道为空阻塞{read(fd[0],buf,32);if(strcmp(buf,quit)0)exit(0);printf(%s\n,buf);} }else{while(1)//循环从终端输入数据,循环往管道写入数据{//scanf(%s,buf);fgets(buf,32,stdin);if(buf[strlen(buf)-1] \n)buf[strlen(buf)-1] \0;write(fd[1],buf,strlen(buf)1);if(strcmp(buf,quit)0)exit(0);}wait(NULL);}close(fd[0]);close(fd[1]);return 0;
}四、有名管道
4.1 特点⭐⭐⭐
可以用于两个不相关的进程之间通信有名管道可以通过路径名指出在文件系统中可见但内容存放在内存里通过文件IO操作遵循先进先出故不支持lseek操作半双工通信
4.2 函数 mkfifo
int mkfifo(const char *filename,mode_t mode);
功能创健有名管道参数 filename有名管道文件名mode权限 返回值成功0失败-1并设置errno号 注意对错误的处理方式 如果错误是file exist时注意加判断如if(errno EEXIST) 执行如下代码 第一次运行 再次运行 处理方式捕捉错误码进行过滤即可
由上面的有名管道特点的第二条可以知道写入有名管道的内容并非存放在文件中而是存在内存也就是说有名管道文件的大小为0下面进行验证 在写后面加一个while死循环运行后会等写完阻塞不读出数据。然后在终端可以查看当前管道文件的大小结果是大小为0
4.3 注意事项⭐⭐
只写方式写阻塞直到另一个进程将读打开只读方式读阻塞直到另一个进程将写打开可读可写管道中无数据读阻塞。
验证1,2 创建两个c文件一个以只读方式打开有名管道从中读数据另一个以只写方式打开同一个有名管道从中写数据。 只读 只写 通过运行可以看到运行了其中任意一个会发生阻塞只有当再运行另一个才可以解除阻塞两个程序得以顺利执行下去。验证了只写方式写阻塞直到另一个进程将读打开 只读方式读阻塞直到另一个进程将写打开。 还可以得知上面程序并不是在read或iwrite发生阻塞而是在open函数处发生了阻塞。
补充如果所有写进程都关闭命名管道则只读进程的读操作会认为到达文件末尾读操作解除阻塞并返回 验证 以只读方式打开有名管道的程序代码1.c 以只写方式打开有名管道程序代码2.c 先执行1.c会发生阻塞再执行2.c2.c不会往管道写入数据保证1.c不会因为管道中有数据而解除阻塞2.c间隔1秒关闭管道可以看到原先阻塞的1.c也会在2.c执行1秒后解除阻塞且read返回值为0。
4.4 练习
通过有名管道实现cp文件复制 方法一两个c文件一个只读管道一个只写管道 3cp_MkfifoToDest.c
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include errno.h
#include fcntl.h
#include unistd.hint main(int argc, char const *argv[])
{if(argc ! 2){printf(Please input %s des\n,argv[0]);return -1;}if(mkfifo(./fifo,0666) 0)//创建有名管道{//处理文件已存在的情况if(errno EEXIST)//EEXTST17{printf(file eexist\n);}else{perror(mkfifo err);return -1;}}//打开管道和目标文件int fd open(./fifo,O_RDONLY);//此处一定不要用可读可写的方式打开//若以可读可写的方式打开管道中无数据则读阻塞if(fd0){perror(open fifo err);return -1;}int dest open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0666);if(fd0){perror(open dest err);return -1;}//循环读管道写目标文件ssize_t s;char buf[32] {0};while ((sread(fd,buf,32)) ! 0)write(dest,buf,s);close(fd);close(dest);return 0;
}3cp_SrcToMkfifo.c
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include errno.h
#include fcntl.h
#include unistd.hint main(int argc, char const *argv[])
{if(argc ! 2){printf(Please input %s src\n,argv[0]);return -1;}if(mkfifo(./fifo,0666) 0)//创建有名管道{//处理文件已存在的情况if(errno EEXIST)//EEXTST17{printf(file eexist\n);}else{perror(mkfifo err);return -1;}}//打开管道和源文件int fd open(./fifo,O_WRONLY);if(fd0){perror(open fifo err);return -1;}int src open(argv[1],O_RDONLY);if(fd0){perror(open src err);return -1;}ssize_t s;char buf[32] {0};while ((sread(src,buf,32)) ! 0){write(fd,buf,s);}close(fd);close(src);return 0;
}运行结果
方法二单个c文件用父子进程实现父进程只写有名管道子进程只读有名管道
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include sys/wait.h
#include errno.h
#include fcntl.h
#include unistd.h
#include stdlib.hint main(int argc, char const *argv[])
{if (argc ! 3){printf(Please iniput %s src dest\n, argv[0]);return -1;}if (mkfifo(./fifo, 0666) 0) //创建有名管道{//处理文件已存在的情况if (errno EEXIST) //EEXTST17{printf(file eexist\n);}else{perror(mkfifo err);return -1;}}//打开管道、源文件、目标文件int src open(argv[1], O_RDONLY);if (src 0){perror(open src err);return -1;}int dest open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);if (dest 0){perror(open dest err);return -1;}ssize_t s;char buf[32] {0};pid_t pid fork(); // 创建子进程if (pid 0){perror(fork err);return -1;}else if (pid 0) //子进程从有名管道中读出数据写到目标文件中{int fd open(./fifo, O_RDONLY); //管道设置为只读if (fd 0){perror(open fifo err);return -1;}while ((s read(fd, buf, 32)) ! 0)write(dest, buf, s);printf(child end...\n);close(fd);exit(0);}else //父进程从源文件读出数据写到有名管道中{int fd open(./fifo, O_WRONLY); //管道设置为只写if (fd 0){perror(open fifo err);return -1;}while ((s read(src, buf, 32)) ! 0)write(fd, buf, s);printf(parent end...\n);close(fd);wait(NULL);}close(src);close(dest);return 0;
}注该程序容易被怀疑最后在子进程的read(fd, buf, 32)会发生阻塞其实不然这里用到了上面的一个要点如果所有写进程都关闭命名管道则只读进程的读操作会认为到达文件末尾读操作解除阻塞并返回
五、无名管道与有名管道对比⭐⭐