IPC和管道简?/span>
本文:http://www.china-pub.com 作?span>: 黄浩?span> (2001-08-08 09:00:00)
1 Interprocess Communication (IPC)和管?span lang="EN-US">Pipes
?span lang="EN-US">UNIX的内核环境中Q要解决的一个首要问题是Q如何控制和处理不同q程之间的通信和数据交换?span lang="EN-US">
本章中我们将通过研究一个简单的实例Q看看在同一台机器的UNIX环境下多个进E是如何q行和被我们控制?span lang="EN-US">
Q?span lang="EN-US">fork()Ҏ(gu)Q?span lang="EN-US">
能够实现q程间通信的方法有Q?span lang="EN-US">
· Pipes
· Signals
· Message Queues
· Semaphores
· Shared Memory
· Sockets
本文先学?fn)如何?span lang="EN-US">Pipes Ҏ(gu)来实C个进E间的通信Q而其它进E间通信的方法我们将在接下来的文?span lang="EN-US">
中详l讨论?span lang="EN-US">
?span lang="EN-US">UNIX环境下可以用两U方式打开一个管道:(x)Formatted Piping方式?span lang="EN-US">Low Level Piping方式?span lang="EN-US">
1.1 popen() -- Formatted Piping
FILE *popen(char *command, char *type)
描述了打开一?span lang="EN-US">I/O道的方法?span lang="EN-US">
其中command参数描述创徏道的进E,type参数描述了管道打开的类型:(x)"r"表示以读方式打开Q?span lang="EN-US">"w"表示?span lang="EN-US">
写方式打开?span lang="EN-US">
popen()的返回值是一个指针流?span lang="EN-US">NULL指针Q出现错误时Q?span lang="EN-US">
使用popen()Ҏ(gu)打开的管道,在用完毕后必须?span lang="EN-US">pclose(FILE *stream)Ҏ(gu)关闭?span lang="EN-US">
用户界面可以通过fprintf()?span lang="EN-US">fscanf()Ҏ(gu)来实现和道的通信?span lang="EN-US">
1.2 pipe() -- Low level Piping
int pipe(int fd[2])
创Z个管道和两个文g描述W:(x)fd[0], fd[1]?span lang="EN-US">
其中fd[0] 文g描述W将用于L作,?span lang="EN-US">fd[1] 文g描述W将用于写操作?span lang="EN-US">
pipe()的成功返回值是0Q如果创建失败将q回-1q将p|原因记录?span lang="EN-US">errno中?span lang="EN-US">
使用int pipe(int fd[2])创徏道的标准编E模式如下:(x)
1Q?span lang="EN-US"> 创徏道Q?span lang="EN-US">
2Q?span lang="EN-US"> 使用fork( )Ҏ(gu)创徏两个Q或多个Q相兌的进E;
3Q?span lang="EN-US"> 使用read()?span lang="EN-US">write()Ҏ(gu)操作道Q?span lang="EN-US">
4Q?span lang="EN-US"> 道使用完毕后用close(int fd)Ҏ(gu)关闭道?span lang="EN-US">
下一D늨序中使用了该U?span lang="EN-US">Low Level Piping的方法,实现了父q程对子q程的写操作Q?span lang="EN-US">
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 应用实例分析
本节提供了一个完整的道应用实例Q其l构说明如下Q?span lang="EN-US">
1Q?span lang="EN-US"> 实例含有两个E序模块plot.c (ȝ?span lang="EN-US">)?span lang="EN-US">plotter.cQ?span lang="EN-US">
2Q?span lang="EN-US"> E序q行?span lang="EN-US">Solaris2.6环境下ƈ必须预先安装?span lang="EN-US">GNU的免费画图Y?span lang="EN-US">gnuplot 在以下目录:(x)/usr/local/bin/Q?span lang="EN-US">
3Q?span lang="EN-US"> E序plot.c调用gnuplotQ?span lang="EN-US">
4Q?span lang="EN-US"> Plot生两个数据流Q?span lang="EN-US">
y = sin(x)
y = sin(1/x)
5Q?span lang="EN-US"> E序创Z个管道:(x)每个数据对应一个管道?span lang="EN-US">
本实例在Solaris2.6?span lang="EN-US">UNIX环境下调试通过?span lang="EN-US">
plot.cE序的源代码如下Q?span lang="EN-US">
/* 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
作者的?sh)子邮g地址是:(x)vong@21cn.com

]]>