2009年3月19日星期四

[转]标准输入输出以及管道操作

UNIX系统程序设计-6-编程语言-电脑网络-搜狐社区: "第六章:标准输入输出以及管道操作

标准输入输出大概所有的操作系统都差不多吧。从键盘输入。从屏幕输出。除非你用的还是打纸带的老家伙。呵呵。
主要说一下管道操作。注意:此处所说的管道操作不是
% cat -n test.c | more
这是在提示符状态下使用管道,把第一个程序(cat)的输出作为输入传给第二个程序(more)。我们现在要在程序中使用的管道原理与此相同。将某一个程序的输出变为另一个程序的输入。

做一个石头剪子布的程序。其中包括一个父程序和一个子程序。注意是两个程序,不是两个函数。也不是两个进程。不过因为父程序运行的时候要通过exec()函数来执行子程序。所以我们也可以把它看成是两个进程。
父进程取得用户的输入(石头S,剪子C,布P中的某一个,P=0,S=1,C=2)并通过管道传给子进程
子进程取得父进程传来的数字,加上自己的PID后做为种子数,生成一个随机数然后被3除,得出来一个余数是0、1或者2。再通过管道传回给父进程。
父进程根据两个数字(用户输入的,以及子进程传回来的)判定胜负,输出

/* parent. */
#include <sys/types.h>
#include <stdio.h>
int main()
{
int i , j ,
st , fd[2] ;
pid_t pid ;
static int result[3][3]={1,0,2,2,1,0,0,1,2};
char argv1[3] , argv2[3] ,
ch ;

ch=getchar();
switch(ch)
{
case 'P': i=0;break;
case 'S': i=1;break;
case 'C': i=2;break;
default:
fprintf( stderr , 'Enter P , S or C , Please!\n' );
exit(1);
}
if( pipe(fd)!=0 ) //建立管道
{
fprintf( stderr , 'PIPE Error !\n' );
exit(1);
}
sprintf( argv1 , '%d' , fd[0] );
sprintf( argv1 , '%d' , fd[1] );

switch( pid=fork() ) // fork出一个新的进程,执行子程序
{
case 0:
if( execl('child','child',argv1,argv2,(char *)0) == (-1)) exit(1);
//执行了子程序
break;
case -1:
fprintf( stderr , 'fork Error !\n' );
exit(1)
}
write( fd[1], &i , sizeof(i) ); //向管道写数据
wait( &st ); //等待子程序结束
read( fd[0] , &j , sizeof(j) ); //从管道读数据
switch(result[j])
{
case 0:
printf( 'You won\n' );
break;
case 1:
printf( 'Same\n' );
break;
case 2:
printf( 'You lost\n' );
}
close(fd[0]);
close(fd[1]);
return 0;
}


/* child.c */
#include <stdio.h>
int main(int argc , char *argv[])
{
int i,j,
read_fd,
write_fd;
read_fd=atoi( argv[1] ); //设定输入用管道
write_fd=atoi( argv[2] ); //设定输出用管道
read( read_fd , &i , sizeof(i) ); //从管道中取得数据
srand( i+getpid() ); //设定随机数的种子数
j=rand()%3; //生成随机数
write( write_fd , &j , sizeof(j) ); //写向管道
close( read_fd );
close( write_fd );
return 0;
}

编译执行父程序即可。

这种管道是用来在父子进程间传递数据的。如同大家在程序中所见:父进程开辟管道,然后生成子进程执行子程序,并将管道参数作为main()函数的参数传给子程序。通过一个相同的管道实现读写。开辟管道时,我们用到了这个函数:

int pipe( int fd[2] ); 开辟一个管道

参数fd[2]是一个有两个元素的数组。可以看成是两个管道的记述子。fd[0]用来读,fd[1]用来写。
返回值: 成功时:0
失败时:-1
读取/写入管道时,我们用到了下面函数

读取管道中的数据
int read( int fd , char *buf , unsigned int nbyte );
向管道中写入数据
int write( int fd , char *buf , unsigned int nbyte );

其中,fd是管道记述子,也就是我们前面说的fd[0]或者fd[1],buf装数据,nbyte指定读/写数据的数量,单位是字节。成功时返回0,失败时返回-1。

由于准备考研。这篇文章耽误了一些时日。最近还有些事,也许下一篇也得几天后才能再贴。
另外,在此向诸位致歉。我的程序是在学校的UNIX下写的,一般是用软盘带回来,写上一篇贴子程序的时候没有带软盘,只好打印出来回来再敲。在输入的时候有一个错误(现已改正)
int main( int argc , char *argvp]);
应为
int main( int argc , char *argv[]);
下一章准备说说UNIX的进程(Process)和信号(signal)。"

没有评论: