发新话题
打印

Linux系统管道和有名管道的通信机制

Linux系统管道和有名管道的通信机制


Linux 进程间通信的几种主要手段。其中管道和有名管道是最早的进程间通信机制之一,管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。 认清管道和有名管道的读写规则是在程序中应用它们的关键,本文在详细讨论了管道和有名管道的通信机制的基础上,用实例对其读写规则进行了程序验证,这样做有利于增强读者对读写规则的感性认识,同时也提供了应用范例。
5 `6 K1 K( d3 i8 _管道概述及相关API应用   
+ t/ E' h: o  \: l管道相关的关键概念   4 g' Y0 t0 X/ {/ f: k. q$ m
管道是Linux支持的最初Unix IPC形式之一,具有以下特点:   
3 N5 f4 Y; y2 D8 W9 j( [2 @管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;   $ ^- j# L& r  W, U
只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);   " k" _- j+ L% i# t
单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。   
* q( M4 e9 k" y; ~数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。   3 N+ W, J; V) O1 ^1 {9 J; B. v
管道的创建:   6 P6 D8 x" q+ h, o* q

! c% |! F$ p0 w6 _; ^1 I& c/ j$ `6 m2 a- s5 C- s; x, d
, [5 p7 l5 I& M$ A

  i' C+ [, O0 ]#include int pipe(int fd[2])/ E/ [8 k+ W6 L
该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。   # P, S& p, K- V5 t
管道的读写规则:   
$ s% U! [2 A# a4 J9 W2 y管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。   6 Y( l6 _* ?+ t3 ]% m3 C8 G) e
从管道中读取数据:如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:(PIPE_BUF在include/Linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF至少为512字节,red hat 7.2中为4096)。   ' L$ L: f% c& J7 t# h, s6 j* R
关于管道的读规则验证:
' O+ \* k) v! W! Q8 w. R# n9 o( e4 Q6 A* r4 {7 z" W8 Y( ^: q* L8 p# ]

* D4 r1 _% \8 |& |
& j' R7 W6 h+ q8 V7 T% e- c5 a8 i
( M9 w# h6 ?# B' e, r, _
* {8 ]( A. o/ C/ Y! R
7 Q9 W: K% C9 \* readtest.c *% i% I( j( K6 @4 b" O* O
#include 3 u/ G0 Q" |9 v% z6 i
#include 4 Y5 ]' t, L  ?
#include
: |4 F. @6 Y1 y% V: b3 rmain()
# `* z5 M7 g. i: P: [0 l{
. t/ d) o# T& aint pipe_fd[2];
% ]! |& b( t* ]; j2 rpid_t pid;" K/ r7 \$ d$ \8 c. Y. q+ y7 k
char r_buf[100];: q5 W/ k/ Y8 O6 X
char w_buf[4];) U* x4 [/ t# L; q9 n$ |
char* p_wbuf;
5 ?3 M3 W6 e- b# M# G3 Yint r_num;
7 `; J( i! H2 D! \+ Z$ y' E9 `int cmd;$ `' d# N1 d5 B( ?: w
; O4 u& O1 J5 A) q
memset(r_buf,0,sizeof(r_buf));1 u) D. @* U  j, I5 E% A
memset(w_buf,0,sizeof(r_buf));
8 W, i6 N( s; O; s+ Ip_wbuf=w_buf;# K7 B9 E& y) N4 G; @
if(pipe(pipe_fd)<0)- u  \, x! A% @( q- U* V5 `
{
+ M# K6 i+ t" nprintf("pipe create error\n");& H  }& D! t" S) z2 R) |; E4 @
return -1;
1 k& O# E, Z# }% f}
0 k( Z! e/ T4 ?: E! S& b6 E- ?) b  U, q. [. i
if((pid=fork())==0)
; l) D/ z  w  S& U{+ K! ?5 p8 E8 ~; @
printf("\n");
# D5 ]) K  `: V) X4 O) {; y! yclose(pipe_fd[1]);8 P. V+ |% Z6 \! t9 L
sleep(3);//确保父进程关闭写端* Y( E% k- w. @% r0 F
r_num=read(pipe_fd[0],r_buf,100);' b5 r: x3 e* d
printf( "read num is %d the data read from the pipe is %d\n",r_num,atoi(r_buf));  |0 l5 d$ ~, E! F6 q, @1 S# A

: q! i5 E  g" _8 |close(pipe_fd[0]);
5 v7 z' k0 K. W# [7 n) Q9 J9 f9 Uexit();$ }3 P8 |$ O0 r1 ~
}
/ i, t8 C) d# `/ `: Kelse if(pid>0), ?5 t; t- U2 P) ^
{% s9 t& s% h  z9 v& ~; }/ _
close(pipe_fd[0]);//read( U/ Z) O  Q4 k; X
strcpy(w_buf,"111");
- S3 V5 i) h! |if(write(pipe_fd[1],w_buf,4)!=-1)
$ D% w/ Z% r' Jprintf("parent write over\n");, u0 J  h$ b5 L! P8 k6 o8 x$ H, X% U
close(pipe_fd[1]);//write7 s2 d, Q; A( G+ ~# E% I' i
printf("parent close fd[1] over\n");
, `* A: i. i4 M3 ^) Csleep(10);9 r. {8 P: K) z6 S8 S$ O
}
8 P6 l9 `" Y) c1 V% w4 v( ~' O# l8 i}, y- W& m% c4 B% {  X

9 `' @, u/ ?0 {, X" t' y( m0 S9 ?: B2 j
程序输出结果:   m8 K- |/ N9 }1 c8 L
- P+ X; ~: L, Q2 u0 x# N

9 t$ G  D6 e  X7 Y8 o/ ^2 H
0 h2 M& o) n. a
. Q; [3 h, n) _+ X" s4 o5 B; |8 q/ ^4 J

" f0 Z" Q% m  _* parent write over9 f* G; C  _5 z4 p, a4 x
* parent close fd[1] over
6 y1 [2 z8 l2 _# i* read num is 4 the data read from the pipe is 111
9 T; F' S( Q: s* e+ E& K
# A2 Q+ u7 o( K# L) C' d  r& C附加结论:管道写端关闭后,写入的数据将一直存在,直到读出为止。



点击图标进入精品网摘收藏 欢迎大家加入网络收藏夹

TOP

发新话题