管道 IPC-管道

 

 内容提要:

  1. 管道简介
  2. 使用无名管道实现一个简单的本地文件服务器
  3. 使用标准I/O函数库提供的管道实现
  4. 使用popen实现本地文件服务器
  5. 有名管道-FIFO
  6. 使用FIFO改写本地文件服务器
  7. 管道和FIFO的额外属性
  8. 使用FIFO将本地文件服务器改写成单服务器多客户端
  9. FIFO和NFS的关系
  10. 字节流和消息
  11. 使用自定义的结构化接口改写单服务多客户端程序
  12. 管道和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]表示管道的写端。

管道
IPC-管道

  管道一般是由一个父进程创建,然后被用来在父子进程间进行通信:

管道
IPC-管道

  在父子进程通过管道进行通信的程序中,一般在父进程中先创建一个管道,然后 fork 出一个子进程,然后在两个进程中关闭不写和不读的两端。

   由于Unix中的管道默认实现是单向的,为了实现双向的,可以用两个单向的管道模拟:

管道
IPC-管道

  2.使用无名管道实现一个简单的本地文件服务器

  使用两个管道实现一个客户端-服务器程序,客户端向服务器请求文件,服务器向客户端输出请求文件的内容:

  管道
IPC-管道

  main函数:

管道
IPC-管道
 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 }
管道
IPC-管道

  client 函数:

管道
IPC-管道
 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] = '

 内容提要:

  1. 管道简介
  2. 使用无名管道实现一个简单的本地文件服务器
  3. 使用标准I/O函数库提供的管道实现
  4. 使用popen实现本地文件服务器
  5. 有名管道-FIFO
  6. 使用FIFO改写本地文件服务器
  7. 管道和FIFO的额外属性
  8. 使用FIFO将本地文件服务器改写成单服务器多客户端
  9. FIFO和NFS的关系
  10. 字节流和消息
  11. 使用自定义的结构化接口改写单服务多客户端程序
  12. 管道和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]表示管道的写端。

管道
IPC-管道

  管道一般是由一个父进程创建,然后被用来在父子进程间进行通信:

管道
IPC-管道

  在父子进程通过管道进行通信的程序中,一般在父进程中先创建一个管道,然后 fork 出一个子进程,然后在两个进程中关闭不写和不读的两端。

   由于Unix中的管道默认实现是单向的,为了实现双向的,可以用两个单向的管道模拟:

管道
IPC-管道

  2.使用无名管道实现一个简单的本地文件服务器

  使用两个管道实现一个客户端-服务器程序,客户端向服务器请求文件,服务器向客户端输出请求文件的内容:

  管道
IPC-管道

  main函数:

管道
IPC-管道
 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 }
管道
IPC-管道

  client 函数:

管道
IPC-管道
 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] = '