IPC和管道簡介(轉)

post0發表於2007-08-09
IPC和管道簡介(轉)[@more@]

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 ");

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 ",i,y1);

fprintf(fp2,"%f %f ",i,y2);

fprintf(fp3,"%f %f ",i,y3);

fprintf(fp4,"%f %f ",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(" ctrl-c caught: Shutting down pipes ");

StopPlot();

printf("closing data files ");

fclose(fp1);

fclose(fp2);

fclose(fp3);

fclose(fp4);

printf("deleting data files ");

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 ";

static char *startplot2 = "plot 'plot21.dat' with lines,

'plot22.dat' with lines ";

static char *replot = "replot ";

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 ";

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

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-938913/,如需轉載,請註明出處,否則將追究法律責任。