Linux 进程间通信 利用管道进行通讯
2 主要内容 传统进程通信 信号通信 管道通信 System V IPC 进程通信 消息队列 共享主存 信号量 Socket 网络进程通信
管道分为无名管道和有名管道 举例 ls –l|more ps –ef|grep ntp
无名管道 它只能用于具有亲缘关系的进程之间的通信(也就是父子 进程或者兄弟进程之间)。 它是一个半双工的通信模式,具有固定的读端和写端。 管道也可以看成是一种特殊的文件,对于它的读写也可以使 用普通的 read() 和 write() 等函数。但是它不是普通的文件,并 不属于其他任何文件系统,并且只存在于内核的内存空间中 。
管道的创建 和关闭 创建管道可以通过调用 pipe() 来实现。 管道是基于文件描述符的通信方式,当一个管道建立时,它 会创建两个文件描述符 fd[0] 和 fd[1] ,其中 fd[0] 约定用于读管 道,而 fd[1] 约定用于写管道,这样就构成了一个半双工的通 道。 管道关闭时只需使用普通的 close() 函数逐个关闭各个文件描 述符。
父子进程之间的管道通信举例 父子进程分别拥有自己的读写通道,为了实现父 子进程之间的读写,只需把无关的读端或写端的 文件描述符关闭即可。此时,父子进程之间就建 立起了一条 “ 子进程写入父进程读取 ” 的通道。
#include #define MAX_DATA_LEN256 #define DELAY_TIME1
int main() {pid_t pid; int pipe_fd[2]; char buf[MAX_DATA_LEN]; const char data[] = "Pipe Test Program"; int real_read, real_write; memset((void*)buf, 0, sizeof(buf)); /* 创建管道 */ if (pipe(pipe_fd) < 0) { printf("pipe create error\n"); exit(1); }
if ((pid = fork()) > 0) {close(pipe_fd[1]); sleep(DELAY_TIME * 3); if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0) {printf("%d bytes read from the pipe is '%s'\n", real_read, buf);} close(pipe_fd[0]); waitpid(pid, NULL, 0); exit(0);} else if (pid == 0) {close(pipe_fd[0]); sleep(DELAY_TIME); if((real_write = write(pipe_fd[1], data, strlen((const char*)data))) != -1) {printf("Parent wrote %d bytes : '%s'\n", real_write, data);} close(pipe_fd[1]); exit(0);}} 关闭写口
有名管道
有名管道的名字为文件路径名,可以用命令创建, 和删除有名管道,它属于 Linux 的特别文件 mkfifo -m 0644 /temp/mypipo rm /temp/mypipo 和一般的文件又有不同:有名管道遵循先进先出 规则,先进入管道的数据被先读出,它们不支持 如 lseek() 等文件定位操作
有名管道创建
有名管道 ( 2 ) 在创建管道成功之后,就可以使用 open() 、 read() 和 write() 这些函数了。与普通文件的开发设置一 样 。 open() 中设置读写模式, O_RDONLY , O_WRONLY O_RDWR 非阻塞标志可以在 open() 函数中设定为 O_NONBLOCK 有关文件操作另外见 word 文档
有名管道 读写规则 对于读进程 若该管道是阻塞打开,且当前 FIFO 内没有数据,则对 读进程而言将一直阻塞到有数据写入。 若该管道是非阻塞打开,则不论 FIFO 内是否有数据, 读进程都会立即执行读操作。即如果 FIFO 内没有数据, 则读函数将立刻返回 0 。 对于写进程 若该管道是阻塞打开,则写操作将一直阻塞到数据可 以被写入。 若该管道是非阻塞打开而不能写入全部数据,则写操 作进行部分写入或者调用失败。
示例(读管道的程序) #include #define MYFIFO"/tmp/myfifo" /* 有名管道文件名 */ #define MAX_BUFFER_SIZEPIPE_BUF /* 定义在于 limits.h 中 */
示例(读管道的程序) int main() {char buff[MAX_BUFFER_SIZE]; int fd; int nread; /* 判断有名管道是否已存在,若尚未创建,则以相 应的权限创建 */ if (access(MYFIFO, F_OK) == -1) {if ((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST)) {printf("Cannot create fifo file\n"); exit(1);}} 管道名字 权限
示例(读管道的程序) /* 以只读阻塞方式打开有名管道 */ fd = open(MYFIFO, O_RDONLY); if (fd == -1) {printf("Open fifo file error\n"); exit(1);} while (1){ memset(buff, 0, sizeof(buff)); if ((nread = read(fd, buff, MAX_BUFFER_SIZE)) > 0) {printf("Read '%s' from FIFO\n", buff);}} close(fd);exit(0);}
还需要一个写管道的程序 ……….
示例(写管道的程序) #include #define MYFIFO"/tmp/myfifo"/* 有名管道文 件名 */ #define MAX_BUFFER_SIZEPIPE_BUF /* 定义在 于 limits.h 中 */
int main(int argc, char * argv[]) /* 参数为即将写入 的字符串 */ {int fd; char buf f[MAX_BUFFER_SIZE]; int nwrite; if(argc <= 1) {printf("Usage:./fifo_write string\n"); exit(1);} sscanf(argv[1], "%s", buff); /* 以只写阻塞方式打开 FIFO 管道 */ fd = open(MYFIFO,O_WRONLY); if (fd == -1){printf("Open fifo file error\n");exit(1);} if ((nwrite = write(fd, buff, MAX_BUFFER_SIZE)) > 0) {printf("Write '%s' to FIFO\n", buff);} close(fd);exit(0);}