多进程通信(IPC)--匿名管道和命名管道
2014-01-27 20:20
316 查看
Unix进程之间的通信主要有四种:管道,共享内存,消息队列,套接字。
1、匿名管道
匿名管道是一种未命名的、单向管道,通常用来在一个父进程和一个子进程之间传输数据。匿名的管道只能实现本地机器上两个进程间的通信,而不能实现跨网络的通信。使用pipes函数来创建管道:
int pipe(int filedes[2]);
该函数通过参数返回两个文件描述符,filedes[0] 用于读,filedes[1] 用于写,事实上,从 filedes[0] 中读出的数据即是向 filedes[1] 中写入的数据。
匿名管道比较简单,看一个例子,代码就不解释了
2、命名管道(FIFO)
FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。
具有如下属性
①与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信;
②FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。
③读写类似文件操作,但不支持诸如lseek()等文件定位操作。
创建函数
该函数的第一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如close、read、write等。
先看代码
读的一端代码:
运行结果
写的一端:
write counts 128
write counts 128
write counts 128
write counts 128
write counts 128
读的一端:
read counts = 128, buf is fdslfl dfjdlfj+0
read counts = 128, buf is fdslfl dfjdlfj+1
read counts = 128, buf is fdslfl dfjdlfj+2
read counts = 128, buf is fdslfl dfjdlfj+3
read counts = 128, buf is fdslfl dfjdlfj+4
read error
分析代码:
①写的一端:先打开并创建一个命名管道,即存在磁盘的文件,查看文件有没有读写权限,可通过mkfifo -m 0644 fifo_server,修改权限,管道的写端打开管道可以设置成阻塞模式,即内核会检查有没有读的一端打开该管道,如果没有则一直阻塞。也可设置成非阻塞模式,即打开后就返回。
②读的一端:打开管道也有阻塞和非阻塞模式,阻塞模式下,需要内核检查到有写该管道的一端才返回,否则一直阻塞,非阻塞是open立即返回
③为了保证读端和写端没有出现缓存大小也引起取值错误,一般声明一个同样大小的缓冲区解决。
1、匿名管道
匿名管道是一种未命名的、单向管道,通常用来在一个父进程和一个子进程之间传输数据。匿名的管道只能实现本地机器上两个进程间的通信,而不能实现跨网络的通信。使用pipes函数来创建管道:
int pipe(int filedes[2]);
该函数通过参数返回两个文件描述符,filedes[0] 用于读,filedes[1] 用于写,事实上,从 filedes[0] 中读出的数据即是向 filedes[1] 中写入的数据。
匿名管道比较简单,看一个例子,代码就不解释了
#include <stdio.h> #include <unistd.h> #define MAX_SIZE 20 #define SUB_COUNT 3 int main() #include <stdio.h> #include <unistd.h> #define MAX_SIZE 20 #define SUB_COUNT 3 int main() { int fd[2]; char w_buf[MAX_SIZE] = {0}; char r_buf[MAX_SIZE] = {0}; pid_t pid; if (pipe(fd) < 0) printf("pipe error\n"); int i = 0; for (; i < SUB_COUNT; ++i) { if ((pid = fork()) < 0) { printf("fork error\n"); } else if (pid == 0) { close(fd[0]); memset(w_buf, 0, sizeof(w_buf)); sprintf(w_buf, "%d", getpid()); int wc = write(fd[1], w_buf, MAX_SIZE); exit(0); } else { memset(r_buf, 0, sizeof(r_buf)); int rd = read(fd[0], r_buf, MAX_SIZE*SUB_COUNT); printf("sub = %d, selfpid = %d-->%s\n", pid, getpid(), r_buf); } } exit(0); return 0; }
2、命名管道(FIFO)
FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。
具有如下属性
①与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信;
②FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。
③读写类似文件操作,但不支持诸如lseek()等文件定位操作。
创建函数
int mkfifo(const char * pathname, mode_t mode)
该函数的第一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如close、read、write等。
先看代码
读的一端代码:
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #define BUF_SIZE 128 int main(int argc, char *argv[]) { char filename[50] = {0}; strcpy(filename, argv[1]); char r_buf[BUF_SIZE] = {0}; //int fd = open(filename, O_RDONLY|O_NONBLOCK,0); int fd = open(filename, O_RDONLY,0); if (fd < 0) { printf("open error fd = %d\n", fd); return 0; } while (1) { int wc = read(fd, r_buf, BUF_SIZE); if (wc <= 0) { printf("read error\n"); break; } printf("read counts = %d, buf is %s \n", wc, r_buf); } return 0; }写的一端代码:
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #define BUF_SIZE 128 int main(int argc, char *argv[]) { char filename[50] = {0}; strcpy(filename, argv[1]); char w_buf[BUF_SIZE] = {0}; if (mkfifo(filename, O_CREAT|O_EXCL) < 0 && errno != EEXIST) printf("create %s error\n", filename); //int fd = open(filename, O_WRONLY|O_NONBLOCK,0); int fd = open(filename, O_WRONLY); if (fd < 0) { if(errno==ENXIO) printf("open error; no reading process\n"); printf("open error fd = %d\n", fd); return 0; } strcpy(w_buf, "fdslfl dfjdlfj"); int i = 0; for (; i < 5; ++i) { char tem[BUF_SIZE] = {0}; sprintf(tem, "%s+%d", w_buf, i); int wc = write(fd, tem, BUF_SIZE); if (wc < 0) { printf("write error\n"); } printf("write counts %d \n", wc); } return 0; }
运行结果
写的一端:
write counts 128
write counts 128
write counts 128
write counts 128
write counts 128
读的一端:
read counts = 128, buf is fdslfl dfjdlfj+0
read counts = 128, buf is fdslfl dfjdlfj+1
read counts = 128, buf is fdslfl dfjdlfj+2
read counts = 128, buf is fdslfl dfjdlfj+3
read counts = 128, buf is fdslfl dfjdlfj+4
read error
分析代码:
①写的一端:先打开并创建一个命名管道,即存在磁盘的文件,查看文件有没有读写权限,可通过mkfifo -m 0644 fifo_server,修改权限,管道的写端打开管道可以设置成阻塞模式,即内核会检查有没有读的一端打开该管道,如果没有则一直阻塞。也可设置成非阻塞模式,即打开后就返回。
②读的一端:打开管道也有阻塞和非阻塞模式,阻塞模式下,需要内核检查到有写该管道的一端才返回,否则一直阻塞,非阻塞是open立即返回
③为了保证读端和写端没有出现缓存大小也引起取值错误,一般声明一个同样大小的缓冲区解决。
相关文章推荐
- linux的IPC进程通信方式-匿名管道(一)
- Linux(七):进程通信IPC(一)之简单的匿名管道编写
- 进程通信:匿名管道和命名管道
- Linux进程通信之管道(匿名,命名)
- Linux(八):进程通信IPC(二)之命名管道
- 利用命名管道实现进程之间的通信 .........
- 9、进程通信之命名管道
- Linux 进程IPC之命名管道
- 采用虚拟命名管道的字符设备和阻塞型I/O实现进程间的通信实现KWIC程序
- linux学习---linux基于文件的IPC(匿名管道pipe,命名管道mkfifo,普通文件,socket文件)
- [Linux管道和IPC]使用信号量和共享内存进行父子进程通信
- 通过匿名管道在进程间双向通信
- 命名管道进程通信
- 利用命名管道实现进程之间的通信 .........
- delphi 与 C++ 进程之间的命名管道通信
- 采用虚拟命名管道的字符设备和阻塞型I/O实现进程间的通信实现KWIC程序
- 命名管道跨进程通信实例1(转)
- Linux间进程通信-----之使用命名管道
- [置顶] 【Linux】 进程通信--匿名管道
- linux下的多进程通信(IPC)原理及实现方案(管道、队列、信号量、共享内存)