Linux-C 进程通信之管道
一、简述
记--对管道的认识与练习。练习进程之间通过管带进行通信。管道包含:有名管道、无名管道(匿名管道)
无名管道pipe:
1,没有名字的
2,半双工
3,通过直系亲属访问继承(因为没有名字,其他程序无法通过获取文件描述符的方式进行操作此管道)
4,管道默认会阻塞
5,不能用lseek定位
6,操作没有原子性
有名管道fifo:(文件)
1,有名字
2,全双工(通信双方可以同时收发数据)
3,可以没有亲属关系(因为有名字,就像文件一样,其他程序可以通过文件名获取文件描述符的方式进行操作此管道)
4,管道默认会阻塞 (例如在没数据的时候去读,就会等待、直到有数据;在管带数据满的时候想写数据,就会进行等待、直到有位置写入)
5,不能用lseek定位 (不能指定的读取 某个位置的数据)
6,操作有原子性 (一个动作要么执行成功、要么执行失败、不会执行到一半)
二、无名管道
功能 | 创建无名管道 |
头文件 | #include <unistd.h> |
原型 | int pipe(int pipefd[2]); |
参数 | pipefd:管道的读写描述符,其中pipefd[0]是读描述符,pipefd[1]是写描述符。 |
返回值 | 成功:返回0 失败:返回-1,并且设置错误号error EFAULT pipefd无效。 |
备注 |
测试代码1:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
char buffer[100];
int retval;
int pipe_fd[2];
pipe(pipe_fd);
pid_t pid;
pid = fork();
if(pid == 0)
{
while(1)
{
memset(buffer, 0, sizeof(buffer));//清空上次数据,防止残留
retval = read(pipe_fd[0], buffer, sizeof(buffer));
if(retval == -1)
{
perror("read pipe failed\n");
exit(EXIT_FAILURE);
}
printf("buffer=[%s]\n", buffer);
if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 )//如果读取到的是exit,则退出
{
break;
}
}
exit(EXIT_SUCCESS);
}
while(1)
{
fgets(buffer, sizeof(buffer), stdin);
buffer[strlen(buffer)-1] = '\0';//fgets()会读取回车
retval = write(pipe_fd[1], buffer, strlen(buffer));
if(retval == -1)
{
perror("write error\n");
break;
}
else if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 )
{
break;
}
}
return 0;
}
运行结果:最后一个exit输出到命令提示符后面是因为:子进程退出慢于主进程,而默认主进程退出之后就会输出命令提示符
测试代码2:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
void signal_handle(int signum)
{
printf("recv SIGPIPE\n");
}
int main(void)
{
char buffer[100];
int retval;
int pipe_fd[2];
pipe(pipe_fd);
pid_t pid;
signal(SIGPIPE, signal_handle);
pid = fork();
if(pid == 0)
{
printf("111\n");
pause();
printf("222\n");
retval = read(pipe_fd[0], buffer, sizeof(buffer));
if(retval == -1)
{
perror("read pipe failed\n");
exit(EXIT_FAILURE);
}
printf("buffer=%s\n", buffer);
exit(EXIT_SUCCESS);
}
fgets(buffer, sizeof(buffer), stdin);
retval = write(pipe_fd[1], buffer, strlen(buffer));
if(retval == -1)
{
perror("write error\n");
}
printf("ok\n");
return 0;
}
运行结果:
三、有名管道
功能 | 创建有名管道(一种特殊的文件) |
头文件 | #include <sys/types.h> #include <sys/stat.h> |
原型 | int mkfifo(const char *pathname, mode_t mode); |
参数 | pathname:管道的名字 mode:创建方式(限定权限之类,类似open()函数) |
返回值 | 成功:返回0 失败:返回-1,并设置error EEXIST 管道已存在 EACCES 权限不足 |
备注 | 读取操作会取走管道数据,关闭管道会清空管道数据。 |
测试代码1:进程间通过管道进行通信(数据传输)
fifo.c文件
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PATH "/home/liang/myfifo"
int main(void)
{
int retval;
if(access(PATH, F_OK))//access()判断文件是否存在,存在返回0
{
retval = mkfifo(PATH, 0665);//创建有名管道、并设置权限
if(retval == -1)
{
perror("creat fifo error\n");
return -1;
}
printf("create fifo success\n");
}
int fifo_fd;
fifo_fd = open(PATH, O_RDWR);//打开有名管道
if(fifo_fd == -1)
{
perror("open fifo error\n");
return -1;
}
char buffer[100];
while(1)
{
fgets(buffer, sizeof(buffer), stdin);
buffer[strlen(buffer)-1] = '\0';//fgets()会读取回车
retval = write(fifo_fd, buffer, strlen(buffer));
if(retval == -1)
{
perror("write error\n");
break;
}
else if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 )
{
break;
}
}
close(fifo_fd);
return 0;
}
fiforead.c文件
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PATH "/home/liang/myfifo"
int main(void)
{
int retval;
if(access(PATH, F_OK))
{
retval = mkfifo(PATH, 0666);
if(retval == -1)
{
perror("creat fifo error\n");
return -1;
}
printf("create fifo success\n");
}
int fifo_fd;
fifo_fd = open(PATH, O_RDWR);
if(fifo_fd == -1)
{
perror("open fifo error\n");
return -1;
}
char buffer[100];
while(1)
{
memset(buffer, 0, sizeof(buffer));
retval = read(fifo_fd, buffer, sizeof(buffer));
if(retval == -1)
{
perror("read error\n");
break;
}
printf("read fifo=[%s]\n", buffer);
if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 )
{
break;
}
}
close(fifo_fd);
return 0;
}
运行结果:
测试代码2:管道关闭之后,管道内容会清空。
fifo.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PATH "/home/liang/myfifo"
int main(void)
{
int retval;
if(access(PATH, F_OK))//access()判断文件是否存在,存在返回0
{
retval = mkfifo(PATH, 0665);//创建有名管道、并设置权限
if(retval == -1)
{
perror("creat fifo error\n");
return -1;
}
printf("create fifo success\n");
}
int fifo_fd;
fifo_fd = open(PATH, O_RDWR);//打开有名管道
if(fifo_fd == -1)
{
perror("open fifo error\n");
return -1;
}
char buffer[100];
memset(buffer, 0, sizeof(buffer));
printf("write data to fifo:");
fgets(buffer, sizeof(buffer), stdin);
buffer[strlen(buffer)-1] = '\0';//fgets()会读取回车
retval = write(fifo_fd, buffer, strlen(buffer));
if(retval == -1)
{
perror("write error\n");
}
printf("write data ok!\n");
close(fifo_fd);
return 0;
}
fiforead.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PATH "/home/liang/myfifo"
int main(void)
{
int retval;
if(access(PATH, F_OK))
{
retval = mkfifo(PATH, 0666);
if(retval == -1)
{
perror("creat fifo error\n");
return -1;
}
printf("create fifo success\n");
}
int fifo_fd;
fifo_fd = open(PATH, O_RDWR);
if(fifo_fd == -1)
{
perror("open fifo error\n");
return -1;
}
char buffer[100];
memset(buffer, 0, sizeof(buffer));
printf("wait for data!\n");
retval = read(fifo_fd, buffer, sizeof(buffer));
if(retval == -1)
{
perror("read error\n");
}
printf("read fifo=[%s]\n", buffer);
printf("read data ok\n");
close(fifo_fd);
return 0;
}
运行结果: