匿名管道
匿名管道只能使有亲缘关系的进程通信
01.利用匿名管道从键盘获取数据显示到屏幕
//匿名管道
#include <stdio.h>
#include <string.h>
#include <unistd.h>
//创建一个匿名管道 fd:文件描述符数组 fd[0]:读端 fd[1]:写端
//成功返回 0 , 失败返回错误代码
int pipe(int fd[2]);
//创建一个匿名管道, 从键盘写入数据到管道, 从管道读取数据, 显示到屏幕
int main()
{
int fds[2];
char buf[1024];
int len = 0;
if(pipe(fds) != 0)
{
perror("pipe");
return -1;
}
//从键盘读数据
//char *fgets(char *buf, int bufsize, FILE *stream);
//参数
//*buf: 字符型指针,指向用来存储所得数据的地址。
//bufsize: 整型数据,指明存储数据的大小。
//*stream: 文件结构体指针,将要读取的文件流。
while(fgets(buf, 1024, stdin) != NULL)
{
len = strlen(buf);
//数据写入管道
//ssize_t write(int fd, const void *buf, size_t nbyte);
//fd:文件描述符;
//buf:指定的缓冲区,即指针,指向一段内存单元;
//nbyte:要写入文件指定的字节数;
//返回值:写入文档的字节数(成功);-1(出错)
if(write(fds[1], buf, len) < 0)
{
perror("write");
break;
}
//清空buf
//void *memset(void *s, int ch, size_t n);
//函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
//memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
memset(buf, 0x00, sizeof(buf));
//从管道读取数据
//函数名: read
//功 能: 从文件中读
//用 法: int read(int handle, void *buf, int nbyte);
if(read(fds[0], buf, 1024) < 0)
{
perror("read");
return -1;
}
len = strlen(buf);
//写到屏幕上
if(write(1, buf, len) < 0)
{
perror("write");
return -1;
}
}
}
02.利用匿名管道实现父子进程间的通信
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
//父子进程通过匿名管道进行通信
//错误处理
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0);
int main(int agrc, char argv[])
{
int fds[2];
//创建匿名管道
if(pipe(fds) != 0)
{
ERR_EXIT("pipe error");
return -1;
}
//创建子进程
pid_t pid = fork();
if(pid == -1)
{
ERR_EXIT("fork error");
return -1;
}
//子进程
if(pid == 0)
{
//关闭子进程的读端
close(fds[0]);
//往写端写入hello
if(write(fds[1], "hello", 5) == -1)
{
ERR_EXIT("write error");
return -1;
}
close(fds[1]);
}
//父进程
//关闭父进程的写端
close(fds[1]);
char buf[10] = {0};
//从读端读入到buf
if(read(fds[0], buf, 5) > 0)
{
printf("buf = %s\n", buf);
}
return 0;
}
命名管道
如果想实现在两个毫不相干的进程间通信,就可以使用命名管道
01.使用命名管道实现文件赋值
src.h
//命名管道, 可用于不相关的进程间通信
//表头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
//定义函数
//int mkfifo(const char* pathname,mode_t mode);
//若成功则返回0,否则返回-1,错误原因存于errno中
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0);
//用命名管道实现文件拷贝
//把数据从abc文件写入管道
int main()
{
//创建一个名为 tmp 的命名管道, 权限664
mkfifo("tmp", 0664);
//以只读方式打开 abc 文件
int in_fd = open("abc", O_RDONLY);
if(in_fd == -1)
{
ERR_EXIT("open error");
}
//以读写方式打开 tmp 管道文件
int out_fd = open("tmp", O_WRONLY);
if(out_fd == -1)
{
ERR_EXIT("open error");
}
char buf[1024] = {0};
int len = 0;
//从in_fd读数据到buf
if((len = read(in_fd, buf, 1024)) > 0)
{
//从buf写数据到out_fd
write(out_fd, buf, len);
}
close(in_fd);
close(out_fd);
return 0;
}
dst.h
//命名管道, 可用于不相关的进程间通信
//表头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
//定义函数
//int mkfifo(const char* pathname,mode_t mode);
//若成功则返回0,否则返回-1,错误原因存于errno中
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0);
//用命名管道实现文件拷贝
//把数据从tmp文件写入abc_cp
int main()
{
int out_fd = open("abc_cp", O_WRONLY | O_CREAT | O_TRUNC, 0664);
if(out_fd == -1)
{
ERR_EXIT("open error");
}
int in_fd = open("tmp", O_RDONLY);
if(in_fd == -1)
{
ERR_EXIT("open error");
}
char buf[1024] = {0};
int len = 0;
if((len = read(in_fd, buf, 1024)) > 0)
{
//从buf写数据到out_fd
write(out_fd, buf, len);
}
close(in_fd);
close(out_fd);
unlink("tmp");
return 0;
}
02.利用命名管道进行server和client之间的对话
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
//利用命名管道实现server和client的对话
#define ERR_EXIT(m) \
do{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0);
int main()
{
umask(0);
//创建 tmp 管道, 权限664
if ( mkfifo("tmp", 0664) < 0 )
{
ERR_EXIT("mkfifo error");
}
//只读打开 tmp 管道文件
int rfd = open("tmp", O_RDONLY);
if(rfd == -1)
{
ERR_EXIT("opne error");
}
char buf[1024] = {0};
while(1)
{
buf[0] = 0;
printf("Please Wait ... \n");
size_t s = read(rfd, buf, sizeof(buf)-1);
if(s > 0)
{
buf[s-1] = 0;
printf("client say: %s\n", buf);
}
if(s == 0)
{
printf("client quit, me too \n");
exit(EXIT_SUCCESS);
}
if(s < 0)
{
ERR_EXIT("read error");
}
}
close(rfd);
return 0;
}
client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
//利用命名管道实现server和client的对话
#define ERR_EXIT(m) \
do{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0);
int main()
{
//读写打开 tmp 管道文件
int wfd = open("tmp", O_WRONLY);
if(wfd < 0)
{
ERR_EXIT("opne error");
}
char buf[1024] = {0};
while(1)
{
buf[0] = 0;
printf("I say: ");
fflush(stdout);
size_t s = read(0, buf, sizeof(buf)-1);
if(s > 0)
{
buf[s] = 0;
write(wfd, buf, sizeof(buf)-1);
}
if(s <= 0)
{
ERR_EXIT("read error");
}
}
close(wfd);
return 0;
}
- 管道提供流式服务
- 一般而言,进程退出,管道释放,所以管道的生命周期随进程
- 内核会对管道操作进行同步与互斥
- 管道是半双工的,数据只能向一个方向流动;需要双方互相通信时,需要建立起两个管道