博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UNIX环境变量--IPC之管道通信
阅读量:2194 次
发布时间:2019-05-02

本文共 4116 字,大约阅读时间需要 13 分钟。

管道通信使用先入先出的原则进行读写,且不能是lseek函数定位读写位置。关注微信公众号,码客资源网

一、无名管道

  无名管道是一种特殊类型的文件,完全由操作系统管理和维护,因为其存储位置只有亲缘关系的进程知道,所以只能用于亲缘关系的进程之间通信,而且,其内核资源会在两个通信进程退出后自动释放,无名管道创建函数为:

//from /usr/include/unistd.hint pipe(int fd[2]);

函数pipe()返回两个文件描述符,其中fd[0]用来完成读操作,fd[1]完成写操作,默认阻塞方式。

以阻塞方式读管道时:

(1)有读进程,无写进程:

  1. 管道内无数据时,立即返回
  2. 管道内数据不足,读出所有数据
  3. 管道内数据充足,读出期望数据

(2)有读进程,有写进程:

  • 管道内无数据时,读进程阻塞
  • 管道内数据不足,读出所有数据
  • 管道内数据充足,读出期望数据

以阻塞方式写管道时:

(1)有写进程,无读进程:

  • 写进程将收到SIGPIPE信号,wirte函数返回-1

(2)有写进程,有读进程,且管道内有写空间:

  • 写入成功

另外可以使用fcntl()函数使用O_NDELAY或O_NONBLOCK属性,设置管道为非阻塞模式。

 

#include 
FILE * popen(const char *command , const char *type );int pclose(FILE *stream);

作用:

    popen函数允许一个程序将另外一个程序作为新进程来启动,并可以传递数据或者通过它接受数据。

    其内部实现为调用 fork 产生一个子进程,执行一个 shell, 以运行命令来开启一个进程,这个进程必须由 pclose() 函数关闭

参数说明:

  command: 是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令。

       type : 只能是读或者写中的一种。如果 type 是 “r” 则文件指针连接到 command 的标准输出;如果 type 是 “w” 则文件指针连接到 command 的标准输入。。

缺点:

    使用popen的不好影响是,针对每个popen调用,不仅要启动一个被请求的程序,还要启动一个shell,即每个popen调用将多启动两个进程。

实例:

#include
#include
#include
int main() { FILE *fp=NULL; FILE *fh=NULL; char buff[128]={0}; memset(buff,0,sizeof(buff)); fp=popen("ls -l","r");//将命令ls-l 通过管道读到fp fh=fopen("shell.c","w+");// 创建一个可写的文件 fread(buff,1,127,fp);//将fp的数据流读到buff中 fwrite(buff,1,127,fh);//将buff的数据写入fh指向的文件中 pclose(fp); fclose(fh); return 0; }

 运行结果:

[lol@localhost practice]$ lspopen popen.c shell.c[lol@localhost practice]$ cat shell.ctotal 12-rwxrwxr-x. 1 lol lol 5478 May 24 15:39 popen-rw-rw-r--. 1 lol lol 473 May 24 15:39 popen.c-rw-rw-r--. 1 lol lol  [lol@localhost practice]$ vim popen.c[lol@localhost practice]$

二、有名管道

有名管道可以通过mknod 命令创建,也可以使用函数mkfifo()创建,可以使用在系统中任意两个进程之间进行通信,且创建的管道文件存储在硬盘上,不会随着进程结束而消失。mknod使用如下:

root@wangmumu-virtual-machine:/home/wangmumu/桌面/shares/FIFO# mknod fifo proot@wangmumu-virtual-machine:/home/wangmumu/桌面/shares/FIFO# ls -l总用量 24prw-r--r-- 1 root   root       0  8月 26 00:30 fifo-rwxr--r-- 1 nobody nogroup  872  8月 25 23:57 fifo_read.c-rwxr--r-- 1 nobody nogroup  884  8月 25 23:52 fifo_write.c-rwxr-xr-x 1 root   root    7613  8月 25 23:57 read-rwxr-xr-x 1 root   root    7651  8月 25 23:52 write

mkfifo()函数声明如下:

// from /usr/include/sys/stat.hint mkfifo(char* path,mode_t mode);

函数的第一个参数为有名管道文件,函数调用时,必须不存在,执行成功返回0,失败返回-1。

(1)如果没有指定O_NONBLOCK方式打开时(默认情况),当进程以写或读的方式打开管道文件,必须有另一个进程以相对应的读或写方式也打开该文件,否则该进程将阻塞在open()位置。

(2)如果指定O_NONBLOCK方式打开,则只读open将立即返回0,但是如果目前没有读进程打开,而直接以写方式打开文件,则open将返回-1,并将errno置为ENXIO,所以建议一般先以读方式打开有名管道。

(3)若两个进程都已打开,但中途某进程退出,则:

    读进程退出,返回SIGPIPE信号

    写进程退出,读进程将不再阻塞,直接返回 0
 

示例:

以下为有名管道代码实现,写进程不断获取终端输入,并写到有名管道上,读进程阻塞读取管道中数据,并将数据打印出来。

写进程代码实现:

#include 
#include
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "fifo"int main(){ int fd = 0; int ret = 0; char buffer[1024] = {0}; if(access(FIFO_NAME,F_OK) == -1) { ret = mkfifo(FIFO_NAME,0755); if(ret != 0) { printf("mkfifo err!\n"); return -1; } } printf("mkfifo success,open O_WRONLY!\n"); fd = open(FIFO_NAME,O_WRONLY); if(fd < 0) { printf("open FIFO_NAME fail!\n"); return -1; } else { while(1) { gets(buffer); //strcpy(buffer,"hello nihao\n"); ret = write(fd,buffer,strlen(buffer)); if(-1 == ret ) { printf("write buffer fail!\n"); return -1; } memset(buffer,0,sizeof(buffer)); sleep(1); } } close(fd); return 0;}

读进程代码实现:

#include 
#include
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "fifo"int main(){ int fd = 0; int ret = 0; char buffer[1024] = {0}; unlink(FIFO_NAME); ret = mkfifo(FIFO_NAME,0755); if(ret != 0) { printf("mkfifo err!\n"); return -1; } printf("mkfifo success,open O_RDONLY!\n"); fd = open(FIFO_NAME,O_RDONLY); printf("zusissiiii\n"); if(fd < 0) { printf("open FIFO_NAME fail!\n"); return -1; } else { while(1) { ret = read(fd,buffer,sizeof(buffer)); if(-1 == ret ) { printf("write buffer fail!\n"); return -1; } printf("FIFO read buffer:%s\n",buffer); memset(buffer,0,sizeof(buffer)); sleep(1); } } close(fd); return 0;}

转载地址:http://swpub.baihongyu.com/

你可能感兴趣的文章
【LEETCODE】36-Valid Sudoku
查看>>
【LEETCODE】205-Isomorphic Strings
查看>>
【LEETCODE】204-Count Primes
查看>>
【LEETCODE】228-Summary Ranges
查看>>
【LEETCODE】27-Remove Element
查看>>
【LEETCODE】66-Plus One
查看>>
【LEETCODE】26-Remove Duplicates from Sorted Array
查看>>
【LEETCODE】118-Pascal's Triangle
查看>>
【LEETCODE】119-Pascal's Triangle II
查看>>
【LEETCODE】88-Merge Sorted Array
查看>>
【LEETCODE】19-Remove Nth Node From End of List
查看>>
【LEETCODE】125-Valid Palindrome
查看>>
【LEETCODE】28-Implement strStr()
查看>>
【LEETCODE】6-ZigZag Conversion
查看>>
【LEETCODE】8-String to Integer (atoi)
查看>>
【LEETCODE】14-Longest Common Prefix
查看>>
【LEETCODE】38-Count and Say
查看>>
【LEETCODE】278-First Bad Version
查看>>
【LEETCODE】303-Range Sum Query - Immutable
查看>>
【LEETCODE】21-Merge Two Sorted Lists
查看>>