一 管道通信:
1,管道:管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程的尾部写入数据,另一个进程的头部读出数据。
2,进程间数据的传递:popen和pclose
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
popen函数允许一个程序将另一个程序作为新进程来启动,并可以传递数据给他或者通过他接收数据。command字符串是要运行的程序名和参数,type 必须是"r"或"w"
pclose函数只在popen启动的进程结束后才返回。如果调用pclose时它仍在运行,pclose将等待该进程的结束。
#include <stdio.h>
#define SIZE 1024
int main()
{
//FILE *popen(const char *command, const char *type);
FILE *fp = popen ("ls","r");
if(fp == NULL)
{
perror("popen fp");
return -1;
}
char buf[SIZE] = {0};
int ret = fread (buf,sizeof(char),SIZE-1,fp);
//printf("%s\n",buf);
FILE *fp2 = popen("ls -l","w");
if(fp2 == NULL)
{
perror("popen fp2");
return -1;
}
fwrite (buf,sizeof(char),ret,fp2);
printf("%s\n",buf);
pclose(fp);
return 0;
}
输出结果为:
[root@promote 7-进程通信]# ./a.out
总计 9
-rwxrwxrwx 1 root root 472 2017-08-13 1-管道.c
-rwxrwxrwx 1 root root 5550 2017-08-13 a.out
1-管道.c
a.out
二 管道类型:无名管道和有名管道
1,无名管道:用于父子进程之间的通信
无名管道由pipe()创建:#include <unistd.h> int pipe(int filedes[2]);
创建一个无名管道:
当一个管道建立时,会创建两个文件描述符:fd[0]用于读管道,fd[1]用于写管道。
int main()
{
//int pipe(int filedes[2]);
int fd[2];
int ret = pipe(fd);
if(ret == -1)
{
perror("pipe ");
return -1;
}
else
{
printf("create success\n");
}
close(fd[0]);
close(fd[1]);
return 0;
}
2,无名管道的读写:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#define SIZE 1024
void children(int *fd)
{
close(fd[1]);//子进程关闭写端
char buf[SIZE];
while(1)
{
int ret = read(fd[0],buf,SIZE-1);
if(ret == -1)
{
perror("read ");
return;
}
buf[ret] = '\0';//字符串末尾设置'\0'
printf("读到%d字节: %s",ret,buf);
}
close(fd[0]);//关闭读端
return;
}
void father(int *fd)
{
close(fd[0]); //父进程关闭读端
char buf[SIZE];
while(1)
{
fgets(buf,SIZE,stdin);
int ret = write (fd[1],buf,strlen(buf));//父进程发送数据
printf("父进程发送%d 字节\n",ret);
}
close(fd[1]);//关闭写端
return;
}
int main()
{
int fd[2]; //创建一个无名管道
int ret = pipe(fd);
if(ret == -1)
{
perror("pipe ");
return -1;
}
pid_t pid = fork(); //创建一个子进程
if(pid == -1)
{
perror("fork ");
return -1;
}
if(pid == 0)
{
children(fd);
}
else
{
father(fd);
}
return 0;
}
父进程一边写入,子进程一边读出:
[root@promote 7-进程通信]# ./a.out
qwe
父进程发送4 字节
读到4字节: qwe
qwe
父进程发送4 字节
读到4字节: qwe
qwe
父进程发送4 字节
读到4字节: qwe
3,用管道实现文件复制:
之前系统调用中讲到可以用read,write复制文件,现在也可以用管道来实现:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SIZE 2048
int children(int *fd)
{
close(fd[1]);
int fd2 = open("4.mmap",O_WRONLY | O_CREAT,0777);
if(fd2 == -1)
{
perror("open fd2 ");
return -1;
}
char buf[SIZE] = {0};
int ret;
while(ret = read(fd[0],buf,SIZE))
{
if(ret == -1)
{
perror("read ");
return -1;
}
write(fd2,buf,ret);
}
printf("read over \n");
close(fd[0]);
close(fd2);
return 0;
}
int father(int *fd)
{
close(fd[0]);
int fd1 = open("3.mmap",O_RDONLY);
if(fd1 == -1)
{
perror("open fd1 ");
return -1;
}
char buf[SIZE] = {0};
int ret;
while(ret = read(fd1,buf,SIZE))
{
if(ret == -1)
{
perror("read ");
return -1;
}
write(fd[1],buf,ret);
}
close(fd[1]);
close(fd1);
return 0;
}
int main()
{
int fd[2]; //创建一个无名管道
int ret = pipe(fd);
if(ret == -1)
{
perror("pipe ");
return -1;
}
pid_t pid = fork(); //创建一个子进程
if(pid == -1)
{
perror("fork ");
return -1;
}
if(pid == 0)
{
children(fd);
}
else
{
father(fd);
}
return 0;
}
文件成功复制:
4,有名管道FIFO:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
创建一个命名管道:
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
//int mkfifo(const char *pathname, mode_t mode);
int ret = mkfifo("/home/fifo",0777);
if(ret == -1)
{
perror("mkfifo ");
return -1;
}
return 0;
}