1,无名管道(pipe)
1,1 pipe介绍
管道是最初的Unix IPC(interprocess communication, 进程间通信)形式。由于管道没有名字,只能用在有亲缘关系的进程间通信。
管道有两种限制:
(1) 它们是半双工的。数据只能在一个方向上流动。
(2) 它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用f o r k,此后父、子进程之间就可应用该管道。
1,2函数类型
管道是由调用pipe函数而创建的。
#include <unistd.h>
int pipe(int pipefd[2]);
经由参数filedes返回两个文件描述符:filedes [ 0 ]为读而打开,filedes [ 1 ]为写而打开。filedes [ 1 ] 的输出是filedes [ 0 ]的输入。
1,3例子
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
int pipe_fd[2];
pid_t child_pid;
char buf[100];
memset(buf,0,sizeof(buf));
if(pipe(pipe_fd) < 0)//创建管道
{
printf("pipe creat failure:%s\n",strerror(errno));
return -1;
}
printf("pipe creat successful\n");
if ((child_pid = fork()) == -1)//创建进程
{
printf("fork creat failure:%s\n",strerror(errno));
return 0;
}
printf("fork creat successful\n");
if(child_pid == 0)
{
//子进程
printf("child_pid start working...\n");
int w_rite= 0;
close(pipe_fd[0]); //管道只能一读一写 ,0读 ,1写
{
strcpy(buf, "hello world");
w_rite= write(pipe_fd[1],buf,strlen(buf)); //进行写操作
if (w_rite != -1)
{
printf("write \n");
}
else
{
printf("write error... \n");
}
close(pipe_fd[1]); //关掉写操作
}
}
else
{ //父进程
int read_len = 0;
close(pipe_fd[1]);//关掉写端
{
read_len = read(pipe_fd[0], buf, 100);//读数据,读到怎么做,读不到怎么做等
printf("p->child pid %d read len %d: %s\n", child_pid, read_len, buf);
}
close(pipe_fd[0]);
}
return 0;
}
2, 有名管道(fifo)
2,1FIFO
有名管道克服了无名管道需要亲缘关系的缺点,所以个人觉得有名管道还是比较有用处的,它和管道一样,也是半双工,先进先出的方式。操作同样和文件类似,但是不支持想lseek等文件操作,严格的先进先出。
2,2函数类型
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
mkfifo函数通过指定的文件路劲(参数pathname)和指定的权限(参数mode)创建了一个FIF,成功返回0,失败返回-1的同时errno会被设置。一旦FIFO被创建,任何进程都可以根据文件路径打开这个并读写这个FIFO。
需要注意的是:
(1)FIFO只能读或写,不能同时以读写方式打开;
(2)以读的方式打开FIFO时,若FIFO的另一端未被打开来写,则打开操作会阻塞;
(3)以写的方式打开FIFO时,若FIFO的另一端未被开打来读,则打开操作也会阻塞。
2,3例子
用FIFO在两个无亲缘关系进程间传递信息。
首先是客户端
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 1024
#define CLIENT_FIFO "client.fifo"
#define SERVER_FIFO "server.fifo"
//允许用户读、用户写、组成员读和其他用户读,
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
void client(int ,int);
int main(int argc, char **argv)
{
int readfd, writefd;
//创建客户端的FIFO
if((mkfifo(CLIENT_FIFO, FILE_MODE) < 0) && (errno != EEXIST))
{
printf("can't create %s", CLIENT_FIFO);
exit(0);
}
//注意打开来读和打开来写的顺序,否则客户端会与服务器互相阻塞,构成死锁
//打开服务器的FIFO
writefd = open(SERVER_FIFO, O_WRONLY, 0);
if (writefd < 0)
{
printf("open serverfd failure\n");
}
printf("serverfd open\n");
//打开客户端的FIFO
readfd = open(CLIENT_FIFO, O_RDONLY, 0);
if(readfd<0)
{
printf("open clientfd failure\n");
}
printf("clientfd open\n");
client(readfd, writefd);
//删除客户端的FIFO
unlink(CLIENT_FIFO);
exit(0);
}
//客户端函数
void client(int readfd,int writefd)
{
size_t len;
ssize_t n;
char buff[MAXLINE];
//从标准输入流获文件名
fgets(buff, MAXLINE, stdin);
//获取文本长度
len = strlen(buff);
//去掉输入的回车
if (buff[len-1] == '\n')
len --;
//将文件名发送给服务器
write(writefd, buff, len);
//接收服务器返回的数据
while ((n = read(readfd, buff, MAXLINE)) > 0)
write(STDOUT_FILENO, buff, n);
}
服务器端
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 1024
#define CLIENT_FIFO "client.fifo"
#define SERVER_FIFO "server.fifo"
//允许用户读、用户写、组成员读和其他用户读
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
void server(int ,int);
int main(int argc, char **argv)
{
int readfd, writefd;
//创建服务器FIFO
if((mkfifo(SERVER_FIFO, FILE_MODE) < 0) && (errno != EEXIST))
{
printf("can't create %s", SERVER_FIFO);
exit(0);
}
printf("create server fifo successful\n");
//注意打开来读和打开来写的顺序,否则服务器会与客户端互相阻塞,构成死锁
//打开服务器FIFO(阻塞直到客户端以写的方式打开)
readfd = open(SERVER_FIFO, O_RDONLY, 0);
if(readfd<0)
{
printf("client failure\n");
}
printf("Client is connected!\n");
writefd = open(CLIENT_FIFO, O_WRONLY, 0);
if(writefd<0)
{
printf("write failure\n");
}
printf("start write\n");
server(readfd, writefd);
//删除服务器的FIFO
unlink(SERVER_FIFO);
exit(0);
}
void server(int readfd,int writefd)
{
int fd;
ssize_t n;
char buff[MAXLINE + 1];
//接收客户端发送的数据
if ((n = read(readfd, buff, MAXLINE)) == 0)
{
printf("end-of-file while reading pathname\n");
return;
}
//添加结束符
buff[n] = '\0';
//根据接收到的文件名打开文件
if ( (fd = open(buff, O_RDONLY)) < 0)
{
//打开文件失败
snprintf(buff + n, sizeof(buff) - n, ": cant't open, %s\n", strerror(errno));
n = strlen(buff);
write(writefd, buff, n);
}
else
{
//打开文件成功,读取文件内容发送给客户端
while ( (n = read(fd, buff, MAXLINE)) > 0)
write(writefd, buff, n);
close(fd);
}
}
在相同文件夹下,创建一个txt类型的文件用来进行测试
先打开一个终端运行fifo_server,再打开一个终端运行fifo_client,
此时服务器管道创建成功后,等待客户端的连接,当客户端打开时的同一瞬间,连接成功并等待客户端发送数据
再在客户端输入text。txt