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;}
首先运行读管道程序,若管道中无数据,就一直阻塞到写入数据