IPC和管道简介

来源:互联网 发布:文字扫描识别软件app 编辑:程序博客网 时间:2024/05/30 07:13

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  


0 0
原创粉丝点击