概述
今天试了下管道,感觉挺有意思的~ 现在才发现,原来进程也有这么多的功能可以实现。
管道分类: 根据进程的相互关系,可以分为:匿名管道与命名管道。
1 匿名管道:管道是父进程和子进程间,或是子进程与子进程间单向的通讯机制,即一个进程发送数据到管道,另外一个进程从管道中读出数据。如果需要双向,或是多项通信机制,则需要建立两个活多个管道.
系统负责两件事:一是写入管道的数据和读出管道的数据的顺序是相同的,二是数据不会在管道中丢失,除非某个进程过早的退出.
建立管道函数为
int pipe(int pipe[2]); //其中pipe[0]是读取数据的描述字,pipe[1]是写数据的描述字
实例:
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
void read_data( int pipes[ ] )
{
int c;
int rc;
close( pipes[ 1 ] ); //由于此函数只负责读,因此将写描述关闭(资源宝贵)
while( (rc = read(pipes[ 0 ], &c, 1)) > 0 ){ //阻塞,等待从管道读取数据
putchar( c ); //int 转为 unsiged char 输出到终端
}
exit( 0 );
}
void write_data( int pipes[ ] )
{
int c;
int rc;
close( pipes[ 0 ] ); //关闭读描述字
while( (c=getchar()) > 0 ){
rc = write( pipes[ 1 ], &c, 1 ); //写入管道
if( rc == -1 ){
perror ("Parent: write");
close( pipes[ 1 ] );
exit( 1 );
}
}
close( pipes[ 1 ] );
exit( 0 );
}
int main( int argc, char *argv[ ] )
{
int pipes[ 2 ];
pid_t pid;
int rc;
rc = pipe( pipes ); //创建管道
if( rc == -1 ){
perror( "pipes" );
exit( 1 );
}
pid = fork( );
switch( pid ){
case -1:
perror( "fork" );
exit( 1 );
case 0:
read_data( pipes ); //相同的pipes
default:
write_data( pipes ); //相同的pipes
}
return 0;
}
上述匿名管道是与进程密切相关的。只有有关系的进程才能使用他们。至于两个不相关的进程则需要用到有名字的管道,即命名管道。
2 命名管道:又称FIFO (FIRST IN FIRST OUT). 它是文件系统中的特殊文件(注意是文件哦,一般我们可以把它放在/tmp/xxxx里). 不同的进程打开相同的命名管道实现类似匿名管道的数据通信。
ps: Unix/Linux 文件系统:包括普通文件,文件目录,与特殊文件(FIFO是其中之一),FIFO文件像普通文件一样,也有读写打开等常用功能。
管道文件删除: 程序中可使用unlink()
接触管道读写阻塞: 使用fcntl()
实例:先编译运行fifoW.c , 再编译运行fifoW.c fifoR的子进程接受管道数据,fifoW负责写
/* fifoR.c 负责从管道文件中读取数据 */
#include
<
stdio.h
>
#include
<
stdlib.h
>
#include
<
sys
/
types.h
>
#include
<
sys
/
stat.h
>
#include
<
string
.h
>
#include
<
fcntl.h
>
#include
<
sys
/
wait.h
>
#include
<
signal.h
>
#define
FIFO_NAME "/tmp/myfifo2"
//
定义宏,指向管道文件的位置
void
read_pipe()
{ //子进程, 处理从管道中读数据
int pipe_fd;
int res;
int c;
int open_mode = O_RDONLY; //设置权限,为只读
pipe_fd = open( FIFO_NAME, open_mode ); //打开管道文件,并设置打开权限,返回int
if( pipe_fd!=-1 ){
while(1){
while( (res = read( pipe_fd, &c, 1 )) > 0 ){ //从管道读数据
putchar( c );
}
fflush( stdout );
}
}else{
exit( 1 );
}
close(pipe_fd);
}
void
signal_handler(
int
n)
{ //受到子进程退出信号,结束子进程
int child_status;
wait( &child_status );
printf( "child exited. " );
}
int
main(
int
argc,
char
*
argv[ ] )
{
int pid;
int child_status;
signal(SIGCHLD, signal_handler); //子进程退出时所发信号
pid = fork(); //创建子进程,使之读取管道数据
int i = 0;
switch(pid){
case -1:
printf("fork error");
exit( 1 );
case 0:
read_pipe();
exit( 0 );
default: //做它自己无聊的事
for(i;i<100;i++){
printf("%d ", i);
fflush( stdout );
sleep(2);
}
}
return 0;
}
/* fifoW.c 负责向管道文件中写数据 */
#include
<
stdio.h
>
#include
<
stdlib.h
>
#include
<
sys
/
types.h
>
#include
<
sys
/
stat.h
>
#include
<
string
.h
>
#include
<
fcntl.h
>
#define
FIFO_NAME "/tmp/myfifo2"
//
定义宏,指向管道文件位置
#define
TEN_MEG ( 1024*1024*10 )
//
文件缓冲区最大值
int
main(
int
argc,
char
*
argv[ ] )
{
int res;
int c;
int pipe_fd;
int open_mode = O_WRONLY; //设置读写权限
int bytes_send = 0;
if( access( FIFO_NAME, F_OK ) == -1 ) { //F_OK : 检查是否有这个文件; 类似还有检查文件可读等,参见man中access中定义
res = mkfifo( FIFO_NAME, 0777 ); //创建管道文件,文件属性为0777,root可读写
if( res != 0 ){ //管道文件不可重名
printf( "Could not create fifo %s ", FIFO_NAME );
exit( 1 );
}
}
pipe_fd = open( FIFO_NAME, open_mode ); //打开管道,并设置打开权限
if( pipe_fd !=-1 ){
while( (c = getchar( )) > 0 ){
res = write( pipe_fd, &c, 1 ); //向管道中写数据
if( res == -1 ){
perror( "write error" );
close( pipe_fd );
exit( 1 );
}
}
close( pipe_fd );
}
return 0;
}
To be continue...
最后
以上就是快乐御姐为你收集整理的尝试linux下c编程之管道的全部内容,希望文章能够帮你解决尝试linux下c编程之管道所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复