一 管道通信:
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;
}