linux编程--管道

来源:互联网 发布:软件企业退税政策 编辑:程序博客网 时间:2024/06/05 04:35

1.一、管道的概念管道是一种队列类型的数据结构,它的数据从一端输入,另一端输出。

  在UNIX中,采用函数pipe创建无名管道,其原型为:

#include<unistd.h>

int pipe(int fildes[2]);/*其中fildes[0]为读而开,fildes[1]为写而开,fildes[1]的输出是fildes[0]的输入*/

实践经验】在进程的通信中,我们无法判断每次通信中报文的字节数,即无法对数据流进行自动拆分,从而发生了上例中字进程一次性读取父进程两次通信的报文情况。为了能正常拆分发送报文,我们常常采用以下几种方法:

 1)固定长度:发送进程每次写入固定字节的数据,接受进程每次读取固定字节的内容,报文中多余部分填充空格或填充0,根据填充0,根据填充的位置,本方法又可以分为左对齐和右对齐两种。

 2)显式长度:每条报文由"长度域"和"数据域"组成,"长度域"大小固定,存储了"数据域"的长度,分为字符串型和整型两种,"数据域"是传输的实际报文数据。接受进程先获取"长度域"数据,转换为"数据域"的长度,再读取相应长度的信息即为"数据域"内容。

 3)短连接。每当进程间需要通信时,创建一个通信线路,发送一条报文后立即废弃这条通信路线。这种方式为Socket通信中很常用。

3.双向管道模型

  管道是进程之间的一种单向交流方法,要实现进程间的双向交流,就必须通过两个管道来完成。创立双向管道的过程如下:

主程序:父子进程双向管道通信实例的主函数如下:

ex:一个父子通信进程间双向管道通信的实例,父进程首先向子进程传送两次数据,再接受进程传送过来的两次数据。为了能够正确拆分数据流,从父进程流向子进程的管道I采用"固定长度"方法传送数据,从子进程流向父进程的管道II采用"显示长度"方法传回数据。

[cpp] view plaincopy
  1. #include<unistd.h>  
  2. #include<stdio.h>  
  3. void main()  
  4. {  
  5.   int fildes1[2],fildes2[2];  
  6.   pid_t pid;  
  7.   char buf[255];  
  8.   if(pipe(fildes1)<0 || pipe(fildes2)<0 )/*创建管道*/  
  9.   {   
  10.     fprintf(stderr,"pipe error!/n");  
  11.     return ;  
  12.   }  
  13.   if((pid= fork())<0)/*创建子进程*/  
  14.   {  
  15.     fprintf(stderr,"fork error!/n");  
  16.     return;  
  17.   }  
  18.   
  19.   if(pid == 0)/*子进程*/  
  20.   {  
  21.     /*-------------------------------------------------*/  
  22.     close(fildes1[1]);  
  23.     close(fildes2[0]);  
  24.     strcpy(buf,ReadG(fildes1[0],10);/*读取管道数据*/  
  25.     fprintf(stderr,"[child] buf =[%s] /n",buf);  
  26.     WriteC(fildes2[1],buf); /*回传父进程*/  
  27.     strcpy(buf,ReadG(fildes1[0],10));  
  28.     fprintf(stderr,"child] buf =[%s]/n",buf);  
  29.     WriteC(fildes2[1],buf);  
  30.     return ;  
  31.   }  
  32.   /*------------------parent process---------------------*/  
  33.   close(fildes1[0]);  
  34.   close(fildes2[1]);  
  35.   WriteG(fildes1[1],"Hello!",10);  
  36.   WriteG(fildes1[1],"World!",10);  
  37.   fpintf(stderr,"[father] buf =[%s]/n",ReadC(fildes2[0]));  
  38.   fprintf(stderr,"[father] buf =[%s]/n'ReadC(fildes2[0]));  

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。
习惯上,标准输入(standard input)的文件描述符是 0,标准输出(standard output)是 1,标准错误(standard error)是 2。尽管这种习惯并非Unix内核的特性,但是因为一些 shell 和很多应用程序都使用这种习惯,因此,如果内核不遵循这种习惯的话,很多应用程序将不能使用。
POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2。这三个符号常量的定义位于头文件 unistd.h。
文件描述符是由无符号整数表示的句柄,进程使用它来标识打开的文件。文件描述符与包括相关信息(如文件的打开模式、文件的位置类型、文件的初始类型等)的文件对象相关联,这些信息被称作文件的上下文。

进程获取文件描述符最常见的方法是通过本机子例程open或create获取或者通过从父进程继承。后一种方法允许子进程同样能够访问由父进程使用的文件。文件描述符对于每个进程一般是唯一的。当用fork子例程创建某个子进程时,该子进程会获得其父进程所有文件描述符的副本,这些文件描述符在执行fork时打开。在由fcntl、dup和dup2子例程复制或拷贝某个进程时,会发生同样的复制过程。
对于每个进程,操作系统内核在u_block结构中维护文件描述符表,所有的文件描述符都在该表中建立索引。

------------------------------------------------------------------------------------------------------------
幻数----新的物理学。原子核是由质子和中子构成,在质子数和中子数为某个特定数值或两者均为这一数值时,原子核的稳定性就比平均值大。这些数值被称为“幻数”。迄今已知的幻数有2、8、14、20、28、50、82、126。

在c语言中,把直接使用的常数叫做幻数。在编程时,应尽量避免使用幻数,因为当常数需要改变时,要修改所有使用它的代码,工作量巨大,还可能有遗漏。因此通常把幻数定义为宏或枚举。建议使用枚举,因为它是编译阶段存在的符号,编译器的提示会更清晰、更准确。
#define ARRAY_SIZE 10
enum{ARRY_SIZE = 10}
-----------------------------------------------------------------------------------------------------------------
串行接口 (Serial Interface) 是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。一条信息的各位数据被逐位按顺序传送的通讯方式称为串行通讯。串行通讯的特点是:数据位的传送,按位顺序进行,最少只需一根传输线即可完成;成本低但传送速度慢。串行通讯的距离可以从几米到几千米;根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种。
--------------------------------------------------------------------------------------------------------------------
打开一个文件需要维护很多数据,不光是权限的问题,内核对每一个打开文件都分配了一个数据结构,而文件描述符则是指向这些数据结构的索引,内核可以通过一个文件描述符查到相应文件的数据。


0 0
原创粉丝点击