进程通信:多个进程需要协调工作,需要进行数据的交换。
管道:是unix中进程通信的一种方式,管道的一端连接着输入另一段连接这数据的输出。
管道(无名管道):用于父子进程之间的通信。
有名管道:由于不同进程之间的通信。
匿名管道:
#include <unistd.h>
int pipe(int fdes[2]) /*创建匿名管道*/
fdes:管道的输入、输出端的描述字。
成功时返回 0,失败时返回 -1
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const int BUFFMAX = 100;
int main()
{
pid_t pid;
int n,mypipe[2];
char buffer[BUFFMAX + 1],*some = "hello world!";
if(pipe(mypipe)) /*创建管道*/
{
fprintf(stderr,"faile!\n");
exit(1);
}
if((pid = fork()) < 0) /*创建子进程*/
{
fprintf(stderr,"faile!\n");
exit(1);
}
if(pid == 0) /*如果是子进程*/
{
close(mypipe[1]); /*关闭子进程管道的输出端*/
n = read(mypipe[0],buffer,BUFFMAX); /*从管道中读取数据*/
fprintf(stdout,"Pid %d Read %d %s\n",getpid(),n,buffer);
}
else
{
close(mypipe[0]); /*关闭父进程管道的输入端*/
n = write(mypipe[1],some,strlen(some)); /*向管道写入数据*/
fprintf(stdout,"Pid %d Write %d %s\n",getpid(),n,some);
}
exit(0);
}
一般通过fork创建子进程是为了调用exec( )系列函数运行新的程序,如果调用exec( )则子进程从父进程继承的文件描述已经被新的程序代替,在调用exec( )函数之前可以先把管道的输入端重定向到标准输入端,从而是新的程序能过通过管道和父进程通信。重定向一般使用dup2( old,new)函数实现,如果描述字new打开则先关闭,再用new代替old,这个函数的操作是原子。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
const int Max = 100;
int main()
{
int fd[2];
pid_t pid;
char buffer[Max];
if(pipe(fd)) /*创建管道*/
{
fprintf(stderr,"make falie!\n");
exit(1);
}
if((pid = fork()) < 0) /*创建子进程*/
{
fprintf(stderr,"pid faile!\n");
exit(1);
}
if(pid == 0) /*如果是子进程*/
{
close(fd[1]); /*关闭子进程管道的输出端*/
dup2(fd[0],0); /*把子进程的输入端重定向到标准输入端*/
close(fd[0]); /*关闭不需要的描述字*/
if(execl("/bin/cat","cat",NULL) < 0) /*调用execl()创建新的程序*/
{
fprintf(stderr,"make falie!\n");
exit(1);
}
}
else /*如果是子进程*/
{
close(fd[0]); /*关闭父进程管道的标准输入*/
fprintf(stdout,"Plase input line date!\n");
dup2(fd[1],1); /*为了使用pets函数,把父进程管道出重定向到标准输出*/
close(fd[1]); /*关闭不用的描述字*/
while(gets(buffer) != NULL)
puts(buffer);
}
exit(0);
}
有名管道(FIFO)
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo (const char *path,mode_t mode); /*创建有名管道*/
path:有名管道的路径级名字。
mode:有名管道的文件权限。
失败返回0
创建管道,并读取内容,如果还没有向管道写入内容,将阻塞等待。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_FILE "fifo_file" /*有名管道的名称*/
#define Max 5
int main()
{
int fifo,fd;
int n;
char buff[Max];
if(access(FIFO_FILE,F_OK) < 0) /*测试文件是否存在*/
{
if(mkfifo(FIFO_FILE,0666) < 0) /*创建管道*/
{
fprintf(stderr,"mkdir falie!\n");
exit(1);
}
}
if((fd = open(FIFO_FILE,O_RDONLY)) < 0) /*打开文件*/
{
fprintf(stderr,"Open falie!\n");
exit(1);
}
printf("%d Open %s\n",getpid(),FIFO_FILE);
while((n = read(fd,buff,Max)) > 0) /*读取管道内容*/
{
fprintf(stdout,"%d read %s\n",getpid(),buff);
}
close(fd); /*关闭文件*/
fprintf(stdout,"%d over\n",getpid());
exit(0);
}
打开文件向管道写入数据,当管道内容还没有读取时将阻塞,等待读取完毕在写入。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define FIFO_FILE "fifo_file"
#define Max 100
int main()
{
int fifo,fd;
int n;
char buff[Max + 1] = "hello fifo";
if((fd = open(FIFO_FILE,O_WRONLY)) < 0) /*打开文件*/
{
fprintf(stderr,"fifo1 Open falie!\n");
exit(1);
}
printf("%d Open %s\n",getpid(),FIFO_FILE);
n = write(fd,buff,strlen(buff)); /*向管道内写入文件*/
fprintf(stdout,"%d write %d\n",getpid(),n);
close(fd); /*关闭文件*/
fprintf(stdout,"%d over\n",getpid());
exit(0);
}