1.概述
进程通信机制包括:
传统的UNIX进程间通信:无名管道、有名管道、信号
System V 进程间通信:消息队列、信号量、共享内存
2.管道通信
2.1无名管道
1.特点
(1)适用具有亲缘关系的进程
(2)是特殊的文件,read(),write()
(3)但不在文件系统中,存在内核中
(4)半双工
2.无名管道的创建与关闭
创建:
int pipe_pid[2];
if ( pipe(pipe_fd) < 0 ){
perror("fail to pipe");
exit(-1);
}
关闭:
close(pipe_fd[0])
3.注意点
(1)管道读端存在时,写入数据才有意义,否则Broken Pipe。
(2)不保证写入的原子性。
(3)父子进程先后次序不保证。
4.代码示例
首先创建管道,而后父进程用fork()创建子进程,最后关闭父进程的写端,关闭子进程的读端,建立管道通信。
#include <stdio.h>
#include <unistd,h>
int main ( void ){
int pipe_fd[2];
if ( pipe(pipe_fd) < 0 )//创建管道
{
perror("piep errpr");
exit(-1);
}
//创建子进程
pid_t pid = fork();
//判错
if ( pid < 0 ){
perror("fork error");
exit(-1);
}
//子进程发送信息
else if (0 == pid){
//1.关闭读端
close(pipe_fd[0]);
//2.写入数据
char buf[20] = {0};
printf("子进程发送数据:");
fgets( buf, sizeof(buf), stdin);
//写入管道
write( pipe_fd[1], buf, strlen(buf) );
//3.关闭写端
close( pipe_fd[1] );
}
//父进程接受消息
else if( pid > 0 ){
//1.关闭写端
close ( pipe_fd[1] );
//2.读取数据
buf[20] = {0};
printf("父进程接收数据:");
read ( pipe_fd[0], buf, strlen(buf) );
//3.关闭读端
close ( pipe_fd[0] );
//收集子进程退出信息
waitpid ( pid, NULL, 0 );
exit(0);
}
}
2.2有名管道
1.特点
(1)适用于互不相关的进程
(2)是文件系统中的文件open write read close,先进先出FIFO
(3)不支持lseek()函数
`lseek()` 是一个系统调用函数。
功能:改变文件读写位置、移动文件指针到文件的任意位置、
以及判断文件指针的位置等。
参数:文件描述符、移动的偏移量和移动的起始位置。
返回值:移动后的文件指针位置,出错 -1。
2.创建有名管道
#include <fcntl.h>
#include <sys/types.h>
//mkfifo( 文件名, 文件权限 );成功0,失败-1.
if ( mkfifo(newfifo, 0664) < 0 ){
perror("fail to mkfifo");
exit(-1);
}
3.有名管道FIFO出错信息
EACCESS:指定路径无可执行权限
EEXIST:指定文件已存在
ENAMETOOLONG:路径名称太长
ENOENT:文件不存在
ENOSPC:空间不足
ENOTDIR:目录存在却非真正的目录
EROFS:指定文件存在于只读文件系统内
4.代码示例
写管道程序:
//fifo_write.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#define MYFIFO "myfifo"
int main( int argc, char* argv[])
{
int fd;
int nwrite;
if (argc < 2){
printf("运行时输入字符串\n");
exit(-1);
}
//以只写方式打开有名管道
fd = open(MYFIFO, O_WRONLY)
if(fd < 0)
{
perror("fail to open fifo");
exit(-1);
}
//向管道中写入字符串
nwrite = write(fd, argv[1], strlen(argv[1]+1) );
if ( nwrite > 0 ){
printf("向FIFO中写入%s\n", argv[1]);
}
close(fd);
return 0;
}
读管道程序:
//fifo_read.c
//头文件同上
int main()
{
char[256];
int fd;
//判断FIFO是否存在
if(access(MYFIFO, F_OK) == -1){ //FIFO不存在
if(mkfifo(MYFIFO, 0664) < 0){
perror("fail to open fifo");
exit(-1);
}
}
//以只读方式打开有名管道
fd = open(MYFIFO, O_RDONLY)
if(fd < 0 ){
perror("fail to open file");
exit(-1);
}
while(1){
memset(buf, 0, sizeof(buf) );
nread = read(fd, buf, 256);
if(nread > 0){
printf("从管道中读取的内容为:%s\n", buf);
}
}
close(fd);
return 0;
}
首先运行读管道程序,若管道中无数据,就一直阻塞到写入数据