IPC和管道简介

作者: 黄浩文
1 Interprocess Communication (IPC)和管道Pipes

   在UNIX的内核环境中,要解决的一个首要问题是:如何控制和处理不同进程之间的通信和数据交换。
本章中我们将通过研究一个简单的实例,看看在同一台机器的UNIX环境下多个进程是如何运行和被我们控制的
(使用fork()方法)。
   能够实现进程间通信的方法有:
   · Pipes
   · Signals
   · Message Queues
   · Semaphores
   · Shared Memory
   · Sockets
   本文先学习如何使用Pipes 方法来实现两个进程间的通信,而其它进程间通信的方法我们将在接下来的文章
中详细讨论。
   在UNIX环境下可以使用两种方式打开一个管道:Formatted Piping方式和Low Level Piping方式。

1.1 popen() -- Formatted Piping

   FILE *popen(char *command, char *type)
   描述了打开一个I/O管道的方法。
   其中command参数描述创建管道的进程,type参数描述了管道打开的类型:"r"表示以读方式打开,"w"表示以
写方式打开。
   popen()的返回值是一个指针流或NULL指针(出现错误时)。
   使用popen()方法打开的管道,在使用完毕后必须用pclose(FILE *stream)方法关闭。

   用户界面可以通过fprintf()和fscanf()方法来实现和管道的通信。

1.2 pipe() -- Low level Piping

   int pipe(int fd[2])
   将创建一个管道和两个文件描述符:fd[0], fd[1]。
   其中fd[0] 文件描述符将用于读操作,而fd[1] 文件描述符将用于写操作。
   pipe()的成功返回值是0,如果创建失败将返回-1并将失败原因记录在errno中。
   使用int pipe(int fd[2])创建管道的标准编程模式如下:
   1) 创建管道;
   2) 使用fork( )方法创建两个(或多个)相关联的进程;
   3) 使用read()和write()方法操作管道;
   4) 管道使用完毕后用close(int fd)方法关闭管道。

   下一段程序中使用了该种Low Level Piping的方法,实现了父进程对子进程的写操作:

   int pdes[2];
   pipe(pdes);
   if ( fork() == 0 )
   {/* child */
   close(pdes[1]); /* not required */
   read( pdes[0]); /* read from parent */
   .....
   }
   else
   { close(pdes[0]); /* not required */
   write( pdes[1]); /* write to child */
   .....
   }

1.4 应用实例分析

   本节提供了一个完整的管道应用实例,其结构说明如下:
   1) 实例含有两个程序模块plot.c (主程序)和plotter.c;
   2) 程序运行在Solaris2.6环境下并必须预先安装了GNU的免费画图软件gnuplot 在以下目录:/usr/local/bin/;
   3) 程序plot.c调用gnuplot;
   4) Plot将产生两个数据流:
   y = sin(x)
   y = sin(1/x)
   5) 程序将创建两个管道:每个数据流对应一个管道。
   本实例在Solaris2.6的UNIX环境下调试通过。

plot.c程序的源代码如下:
/* plot.c - example of unix pipe. Calls gnuplot graph drawing package to draw
graphs from within a C program. Info is piped to gnuplot */
/* Creates 2 pipes one will draw graphs of y=0.5 and y = random 0-1.0 */ 

/* the other graphs of y = sin (1/x) and y = sin x */

/* Also user a plotter.c module */
/* compile: cc -o plot plot.c plotter.c */

#include "externals.h"
#include
#define DEG_TO_RAD(x) (x*180/M_PI)

double drand48();
void quit();
FILE *fp1, *fp2, *fp3, *fp4, *fopen();

main()
{ float i;
float y1,y2,y3,y4;

/* open files which will store plot data */
if ( ((fp1 = fopen("plot11.dat","w")) == NULL)
((fp2 = fopen("plot12.dat","w")) == NULL)
((fp3 = fopen("plot21.dat","w")) == NULL)
((fp4 = fopen("plot22.dat","w")) == NULL) )
{ printf("Error can't open one or more data files/n");
exit(1);
}

signal(SIGINT,quit); /* trap ctrl-c call quit fn */
StartPlot();
y1 = 0.5;
srand48(1); /* set seed */
for (i=0;;i+=0.01) /* increment i forever use ctrl-c to quit prog */
{ y2 = (float) drand48();
if (i == 0.0)
y3 = 0.0;
else
y3 = sin(DEG_TO_RAD(1.0/i));
y4 = sin(DEG_TO_RAD(i));

/* load files */
fprintf(fp1,"%f %f/n",i,y1);
fprintf(fp2,"%f %f/n",i,y2);
fprintf(fp3,"%f %f/n",i,y3);
fprintf(fp4,"%f %f/n",i,y4);
/* make sure buffers flushed so that gnuplot */
/* reads up to data file */
fflush(fp1);
fflush(fp2);
fflush(fp3);
fflush(fp4);

/* plot graph */
PlotOne();
usleep(250); /* sleep for short time */
}
}

void quit()
{ printf("/nctrl-c caught:/n Shutting down pipes/n");
StopPlot();

printf("closing data files/n");
fclose(fp1);
fclose(fp2);
fclose(fp3);
fclose(fp4);
printf("deleting data files/n");
RemoveDat();
}
The plotter.c module is as follows:
/* plotter.c module */
/* contains routines to plot a data file prodUCed by another program */
/* 2d data plotted in this version */
/**********************************************************************/
#include "externals.h"

static FILE *plot1,
*plot2,
*ashell;

static char *startplot1 = "plot [] [0:1.1]'plot11.dat' with lines,
'plot12.dat' with lines/n";
static char *startplot2 = "plot 'plot21.dat' with lines,
'plot22.dat' with lines/n";
static char *replot = "replot/n";
static char *command1= "/usr/local/bin/gnuplot> dump1";
static char *command2= "/usr/local/bin/gnuplot> dump2"; 
static char *deletefiles = "rm plot11.dat plot12.dat plot21.dat plot22.dat";
static char *set_term = "set terminal x11/n";

void
StartPlot(void)
{ plot1 = popen(command1, "w");
fprintf(plot1, "%s", set_term);
fflush(plot1);
if (plot1 == NULL)
exit(2);
plot2 = popen(command2, "w");
fprintf(plot2, "%s", set_term);
fflush(plot2);
if (plot2 == NULL)
exit(2);
}
void
RemoveDat(void)
{ ashell = popen(deletefiles, "w");
exit(0);
}
void
StopPlot(void)
{ pclose(plot1);
pclose(plot2);
}
void
PlotOne(void)
{ fprintf(plot1, "%s", startplot1);
fflush(plot1);
fprintf(plot2, "%s", startplot2);
fflush(plot2);
}
void
RePlot(void)
{ fprintf(plot1, "%s", replot);
fflush(plot1);
}
The header file externals.h contains the following:
/* externals.h */
#ifndef EXTERNALS
#define EXTERNALS

#include
#include
#include

/* prototypes */

void StartPlot(void);
void RemoveDat(void);
void StopPlot(void);
void PlotOne(void);
void RePlot(void);
#endif

作者的电子邮件地址是:vong@21cn.com 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值