UNIX网络编程卷2进程间通信读书笔记-管道
来源:互联网 发布:cpi最新数据 编辑:程序博客网 时间:2024/05/01 09:32
(笔记从chinaunix copy过来的,然后自己看书的时候把认为需要注意的地方添加上,方便复习)
一.管道
管道的名称很形象,它就像是一个水管,我们从一端到水然后水从令一端流出。不同的是这里说的管道的两边都是进程。从一端往管道里写数据,其它进程可以从管道的另一端的把数据读出,从而实现了进程间通信的功能。
管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
1.管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
2.只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
数据的读出和写入:管道是半双工的,数据只能在一个方向上流动。一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
1.1管道的创建
管道是由调用pipe函数而创建的。
1.
名称::
pipe
功能:
创建管道
头文件:
#include <unistd.h>
函数原形:
int pipe(int filedes[2]);
参数:
返回值:
若成功返回0,若出错则返回-1
Linux用函数pipe来创建管道,经由参数filedes返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。
/*14_1.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
int n;
int fd[2];
pid_t pid;
char line[1024];
if(pipe(fd)<0) /*建立管道*/
perror(“pipe error”);
if((pid=fork())<0) /*创建子进程*/
perror(“fork error”);
else if(pid==0) /*如果是子进父程*/
{
close(fd[0]); /*关闭读描述符*/
write(fd[1],”I’m child,hello father!”,23);/*往管道里写数据*/
}
else /*如果是父进程*/
{
close(fd[1]); /*关闭写描述符*/
wait(); /*等待子进程结束*/
n=read(fd[0],line,1024); /*从管道里读数据,读到缓冲数组中*/
write(STDOUT_FILENO,line,n); /*把缓冲区的数据写道屏幕上*/
}
exit(0);
}
程序先创建一个管道,而后创建一个子进程。让子进程向管道里写数据,让父进程从管道读数据,程序在写个读之前都把不用的描述符关掉。这要做的好处是提高了安全性,因为如果父子进程同时往管道里写将发生错误。
1.2管道的读写规则
管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。
从管道中读取数据:如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0; 当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。
向管道中写入数据:向管道中写入数据时,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。
1.3管道的局限性
管道的主要局限性正体现在它的特点上:
只支持单向数据流;
只能用于具有亲缘关系的进程之间;
没有名字;
管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;
1.4管道的其它操作函数
2.
名称::
popen
功能:
process I/O
头文件:
#include <stdio.h>
函数原形:
FILE *popen(const char *cmdstring,const char *type);
参数:
cmdstring 要执行的程序
type 连接端口
返回值:
若成功则为文件指针,若出错则为NULL。
这两个函数执行过程是:先创建一个管道,调用fork产生一个子进程,然后关闭管道的不使用端,执行一个shell以运行命令,然后等待命令终止。
函数popen先执行fork,然后调用exec以执行cmdstring,并且返回一个标准I/O文件指针。如果type是“r”,则文件指针连接到cmdstring的标准输出。如果type是”w”,则文件指针连接到cmdstring的标准输入。
3.
名称::
pclose
功能:
process I/O
头文件:
#include <stdio.h>
函数原形:
int pclose(FILE *fp);
参数:
fp 标准I/O流
返回值:
cmdstring的终止状态,若出错则为-1。
pclose函数关闭标准I/O流,等待命令执行结束,然后返回shell的终止状态。
下面就是利用这两个函数,把从文件中读入的数据送至分页程序。
/*14_2.c*/
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#define PAGER “${PAGER:-more}”
#define MAXLINE 10000
int main(int argc,char *argv[])
{
char line[MAXLINE];
FILE *fpin,*fpout;
if((fpin=fopen(argv[1],”r”))==NULL) /*打开文件*/
perror(“fopen error”);
if((fout=popen(PAGER,”w”))==NULL) /*创建子进程,然后运行PAGER分页程序,并使fout流连接到分页程序(PAGER)的标准输入*/
perror(“popen error”);
while(fgets(line,MAXLINE,fpin)!=NULL) /*从argc[1]文件读数据,一次读一行,存入line缓冲区*/
{
if(fputs(line,fpout)==EOF) /*把从缓冲区读入的数据写入管道,通过管道输入到分页程序(PAGER)的标准输入*/
perror(“fputs error”);
}
if(pclose(fpout)== -1)
perror(“pclose error”);
exit(0);
}
程序从先文件读数据,把读的数据存入缓冲区,然后创建子进程,让子进程创建管道并使管道的一端连接到分页程序的标准输入。最后父进程把缓冲区的数据写入管道的另一端,从而实现了输出从定向的功能。
popen特别适用于构造简单的过滤程序,它变换运行命令的输入或输出。使用popen,可以在应用程序和输入之间插入一个程序以便对输入进行变换处理。下面的程序是一个简单的过滤程序,它只是将标准输入复制到标准输出,在复制时将所有大写字符变换为小写字符。在写了一行之后,对标准输出进行了冲洗。
/*14_3.c 过滤程序*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int c;
while((c=getchar())!=EOF) /*获得字符*/
{
if(isupper(c)) /*判断是否是大写字母*/
c=tolower(c)); /*把大写字符转化为小写*/
if(putchar(c)=EOF) /*输出转换后的字母*/
perror(“output error”);
if(c==’\n’)
fflush(stdout); /*将缓冲区的数据输入到标准输出*/
}
exit(0);
}
先编译它,然后我们在下面的程序用popen调用它。可能大家不明白上面的几个函数,我简要介绍一下.
int isupper(int c);若ch是大写字母('A'-'Z')返回非0值,否则返回0。
int tolower(int c);如果c为大写英文字母,则返回对应的小写字母;否则返回原来的值.
int fflush( FILE *stream ); fflush 是用来将流清空的函数,如果流跟文件绑定为输出的模式, 那么将会把流中的内容写入文件。
/*14_4.c*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#define MAXLINE 100
int main(void)
{
char line[MAXLINE];
FILE *fpin;
if((fpin=popen(“./14_3”, “r”))==NULL) /*打开过滤程序*/
perror(“popen error”);
for( ; ; )
{
fputs(“prompt> “,stdout); /*输出提示信息*/
fflush(stdout); /*刷新缓冲区*/
if(fgets(line,MAXLINE,fpin)==NULL) /*从标准输入读数据存放到缓冲区中*/
break;
if(fputs(line,stdout)==EOF) /*把缓冲区数据写到标准输出(屏幕)。
perror(“fput error”);
}
if(fclose(fpin)== -1)
perror(“pclose error”);
putchar(‘\n’);
exit(0);
}
上面的两个程序要在一个文件夹下运行,程序会把用户输入的大写字母转换为小写。我们经常用popen/pclose处理输入和输出,使他们格式统一。方便程序处理。
- UNIX网络编程卷2进程间通信读书笔记-管道
- UNIX网络编程卷2进程间通信读书笔记(二)—管道 (2)
- UNIX网络编程卷2进程间通信读书笔记(三)—有名管道 (2)
- UNIX网络编程卷2进程间通信读书笔记(二)—管道 (1)
- UNIX网络编程卷2进程间通信读书笔记(三)—有名管道 (1)
- UNIX网络编程卷2进程间通信读书笔记—有名管道
- UNIX网络编程卷2进程间通信读书笔记汇总
- UNIX网络编程卷2进程间通信读书笔记汇总
- UNIX网络编程卷2进程间通信读书笔记(一)—概述
- UNIX网络编程卷2进程间通信读书笔记(四)—XSI IPC
- UNIX网络编程卷2进程间通信读书笔记—概述
- UNIX网络编程卷2进程间通信读书笔记—System V消息队列
- UNIX网络编程卷2进程间通信读书笔记----记录锁
- UNIX网络编程卷2进程间通信读书笔记—Posix信号量
- UNIX网络编程卷2进程间通信读书笔记 共享内存区
- UNIX网络编程 卷2:进程间通信
- Unix网络编程--进程间通信--管道通信
- 《UNIX网络编程 卷2》 笔记: 管道
- 【LeetCode】-Construct Binary Tree from Inorder and Postorder Traversal
- UISearchbar去除背景色的方法,适合iOS5/6/7/8.0beta
- 图解TCP/IP协议
- Objective-C 中的CRC32验证
- linux系统监控图表展示--nmon和nmon analyser
- UNIX网络编程卷2进程间通信读书笔记-管道
- 什么是渗透测试
- location.href、parent.location.href、top.location.href、 window.open实现页面跳转
- Delphi下SPCOMM串口编程(转)
- ios layer的一些学习
- 参数错误。 (异常来自 HRESULT:0x80070057 (E_INVALIDARG))
- 转自汇编网: 高三老师给大一学生的一封信(感动!)
- 第五九八章 全息头盔出问题了
- css实用布局口诀