管道 IPC-管道
内容提要:
- 管道简介
- 使用无名管道实现一个简单的本地文件服务器
- 使用标准I/O函数库提供的管道实现
- 使用popen实现本地文件服务器
- 有名管道-FIFO
- 使用FIFO改写本地文件服务器
- 管道和FIFO的额外属性
- 使用FIFO将本地文件服务器改写成单服务器多客户端
- FIFO和NFS的关系
- 字节流和消息
- 使用自定义的结构化接口改写单服务多客户端程序
- 管道和FIFO的限制
1.管道简介
Unix中的进程间通信方式之一是通过管道实现的,管道分为有名管道和无名管道,对于有名管道FIFO,可以实现没有亲缘关系的进程间通信,而对于无名管道,可以实现父子进程间的通信。
管道这种IPC存在的意义是为了实现进程间消息的传递。无名管道是Unix最初的IPC形式,但是由于无名管道的局限性,后来出现了有名管道FIFO,这种管道由于可以在文件系统中创建一个名字,所以可以被没有亲缘关系的进程访问。
管道打开后的标识是以文件描述符的形式提供的,可以使用Unix系统中的read和write系统调用访问。
管道的实现形式有多种,在一些系统中,管道被实现为全双工的,在管道的一端既可以读也可以写,但是Posix.1和Unix 98只要求半双工管道,在Linux系统中,管道是半双工的。
IPC类型 |
持续性 |
用于打开或创建IPC的名字空间 |
IPC打开后的标识 |
fork, exec和exit对IPC对象的影响 |
||
fork |
exec |
_exit |
||||
管道 |
随进程 |
没有名字 |
描述符 |
子进程取得父进程的所有打开着的描述符的副本 |
所有打开着的描述符继续打开着,除非已经设置描述符的FD_CLOEXEC位 |
关闭所有打开着的描述符,最后一个关闭时删除管道或FIFO中残留的所有数据 |
FIFO |
路径名 |
Unix中的无名管道是通过 pipe 函数创建的,该函数创建了一个半双工的管道。
1 #include <unistd.h> 2 3 int pipe(int fd[2]); 4 5 返回值:成功返回0,出错返回-1
函数通过参数fd[2]返回两个描述符,fd[0]表示管道的读端,fd[1]表示管道的写端。
管道一般是由一个父进程创建,然后被用来在父子进程间进行通信:
在父子进程通过管道进行通信的程序中,一般在父进程中先创建一个管道,然后 fork 出一个子进程,然后在两个进程中关闭不写和不读的两端。
由于Unix中的管道默认实现是单向的,为了实现双向的,可以用两个单向的管道模拟:
2.使用无名管道实现一个简单的本地文件服务器
使用两个管道实现一个客户端-服务器程序,客户端向服务器请求文件,服务器向客户端输出请求文件的内容:
main函数:
1 /* 2 * use pipo to communicate between server and client 3 * */ 4 5 #include <stdio.h> 6 #include <unistd.h> 7 #include <sys/wait.h> 8 #include <sys/types.h> 9 #include <string.h> 10 #include <stdlib.h> 11 #include <errno.h> 12 #include <fcntl.h> 13 14 #define _err(msg) 15 { 16 fprintf(stderr, "error : %s -- %s ", msg, strerror(errno)); 17 exit(-1); 18 } 19 20 #define MAX_SIZE 1024 21 22 int 23 main(void) 24 { 25 int fd1[2], fd2[2]; 26 pid_t pid; 27 28 pipe(fd1); 29 pipe(fd2); 30 31 if((pid = fork()) < 0) 32 _err("fork fail"); 33 if(pid > 0) 34 { 35 /*parent*/ 36 close(fd1[1]); 37 close(fd2[0]); 38 server(fd1[0], fd2[1]); 39 printf("server stoped "); 40 waitpid(pid, NULL, 0); 41 } 42 else 43 { 44 close(fd1[0]); 45 close(fd2[1]); 46 client(fd2[0], fd1[1]); 47 printf("client stoped "); 48 exit(0); 49 } 50 return 0; 51 }
client 函数:
1 void 2 client(int readfd, int writefd) 3 { 4 char buffer[MAX_SIZE]; 5 size_t size; 6 printf("client is start ... "); 7 printf("input the filename : "); 8 fgets(buffer, MAX_SIZE, stdin); 9 size = strlen(buffer); 10 if(buffer[size - 1] == ' ') 11 size--; 12 if(write(writefd, buffer, size) <= 0) 13 _err("write to server fail"); 14 while((size = read(readfd, buffer, MAX_SIZE)) > 0) 15 { 16 buffer[size] = '
内容提要:
- 管道简介
- 使用无名管道实现一个简单的本地文件服务器
- 使用标准I/O函数库提供的管道实现
- 使用popen实现本地文件服务器
- 有名管道-FIFO
- 使用FIFO改写本地文件服务器
- 管道和FIFO的额外属性
- 使用FIFO将本地文件服务器改写成单服务器多客户端
- FIFO和NFS的关系
- 字节流和消息
- 使用自定义的结构化接口改写单服务多客户端程序
- 管道和FIFO的限制
1.管道简介
Unix中的进程间通信方式之一是通过管道实现的,管道分为有名管道和无名管道,对于有名管道FIFO,可以实现没有亲缘关系的进程间通信,而对于无名管道,可以实现父子进程间的通信。
管道这种IPC存在的意义是为了实现进程间消息的传递。无名管道是Unix最初的IPC形式,但是由于无名管道的局限性,后来出现了有名管道FIFO,这种管道由于可以在文件系统中创建一个名字,所以可以被没有亲缘关系的进程访问。
管道打开后的标识是以文件描述符的形式提供的,可以使用Unix系统中的read和write系统调用访问。
管道的实现形式有多种,在一些系统中,管道被实现为全双工的,在管道的一端既可以读也可以写,但是Posix.1和Unix 98只要求半双工管道,在Linux系统中,管道是半双工的。
IPC类型 |
持续性 |
用于打开或创建IPC的名字空间 |
IPC打开后的标识 |
fork, exec和exit对IPC对象的影响 |
||
fork |
exec |
_exit |
||||
管道 |
随进程 |
没有名字 |
描述符 |
子进程取得父进程的所有打开着的描述符的副本 |
所有打开着的描述符继续打开着,除非已经设置描述符的FD_CLOEXEC位 |
关闭所有打开着的描述符,最后一个关闭时删除管道或FIFO中残留的所有数据 |
FIFO |
路径名 |
Unix中的无名管道是通过 pipe 函数创建的,该函数创建了一个半双工的管道。
1 #include <unistd.h> 2 3 int pipe(int fd[2]); 4 5 返回值:成功返回0,出错返回-1
函数通过参数fd[2]返回两个描述符,fd[0]表示管道的读端,fd[1]表示管道的写端。
管道一般是由一个父进程创建,然后被用来在父子进程间进行通信:
在父子进程通过管道进行通信的程序中,一般在父进程中先创建一个管道,然后 fork 出一个子进程,然后在两个进程中关闭不写和不读的两端。
由于Unix中的管道默认实现是单向的,为了实现双向的,可以用两个单向的管道模拟:
2.使用无名管道实现一个简单的本地文件服务器
使用两个管道实现一个客户端-服务器程序,客户端向服务器请求文件,服务器向客户端输出请求文件的内容:
main函数:
1 /* 2 * use pipo to communicate between server and client 3 * */ 4 5 #include <stdio.h> 6 #include <unistd.h> 7 #include <sys/wait.h> 8 #include <sys/types.h> 9 #include <string.h> 10 #include <stdlib.h> 11 #include <errno.h> 12 #include <fcntl.h> 13 14 #define _err(msg) 15 { 16 fprintf(stderr, "error : %s -- %s ", msg, strerror(errno)); 17 exit(-1); 18 } 19 20 #define MAX_SIZE 1024 21 22 int 23 main(void) 24 { 25 int fd1[2], fd2[2]; 26 pid_t pid; 27 28 pipe(fd1); 29 pipe(fd2); 30 31 if((pid = fork()) < 0) 32 _err("fork fail"); 33 if(pid > 0) 34 { 35 /*parent*/ 36 close(fd1[1]); 37 close(fd2[0]); 38 server(fd1[0], fd2[1]); 39 printf("server stoped "); 40 waitpid(pid, NULL, 0); 41 } 42 else 43 { 44 close(fd1[0]); 45 close(fd2[1]); 46 client(fd2[0], fd1[1]); 47 printf("client stoped "); 48 exit(0); 49 } 50 return 0; 51 }
client 函数:
1 void 2 client(int readfd, int writefd) 3 { 4 char buffer[MAX_SIZE]; 5 size_t size; 6 printf("client is start ... "); 7 printf("input the filename : "); 8 fgets(buffer, MAX_SIZE, stdin); 9 size = strlen(buffer); 10 if(buffer[size - 1] == ' ') 11 size--; 12 if(write(writefd, buffer, size) <= 0) 13 _err("write to server fail"); 14 while((size = read(readfd, buffer, MAX_SIZE)) > 0) 15 { 16 buffer[size] = '