博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux学习记录--匿名管道通讯
阅读量:4213 次
发布时间:2019-05-26

本文共 9678 字,大约阅读时间需要 32 分钟。

匿名管道通讯

管道是Linux支持的最初Unix IPC形式之一,具有以下特点:

1.管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;

2.只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

 

什么是管道

管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

 

数据的读出和写入

一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

管道的创建

#include int pipe(int fd[2])

管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,

 

管道的规则

1.      当管道内容长度为0时,读端将处于阻塞状态,等待写端向管道写入内容

2.      当写端数据长度小于缓冲区长度时,数据将以原子性写入缓冲区。

 

对读进程来说:

3.      当写端被关闭时,所有数据被读出后,read返回0。

4.      当写端未被关闭时,所有数据被读出后,读端阻塞。

 

对写进程来说:

5.      当读端关闭时,如写端数据长度大于管道最大长度时,写完管道长度时,产生信号SIGPIPE后退出程序。(以存入管道的数据读进程可以读取到)

6.      当读端未被关闭时,如写端数据长度大于管道最大长度时,写完管道长度时,写端将处于阻塞状态

规则分析1

#include
#include
#include
#include
#include
#include
int main() { int fd[2]; pid_t cid; if (pipe(fd) == -1) { perror("管道创建失败!"); exit(1); } cid = fork(); switch (cid) { case -1: perror("子进程创建失败"); exit(2); break; case 0: close(fd[1]); char message[1000]; int num = read(fd[0], message, 1000); printf("子进程读入的数据是:%s,长度是=%d", message, num); close(fd[0]); break; default: close(fd[0]); char *writeMsg = "父进程写入的数据!"; sleep(10);//1 write(fd[1], writeMsg, strlen(writeMsg)); close(fd[1]); break; } return 0;}

[root@ Release 18$] ps -C processcomm -opid,ppid,stat,cmd

 PID  PPID STAT CMD

 5973 2488 S   /root/workspace/processcomm/Release/processcomm

 5976 5973 S   /root/workspace/processcomm/Release/processcomm

=>读端由于阻塞中,其所在进程(子进程)处于sleep状态

 

控制台输出

父进程工作PID=5973,PPID=2488

子进程工作PID=5976,PPID=5973

子进程读入的数据是:父进程写入的数据!,长度是=27

 

规则分析2 

switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[0]);		const long int writesize=4000;		char writeMsg[writesize];		int i;		for(i=0;i

控制台输出

父进程工作PID=7072,PPID=2488

父进程写入的数据长度是=4001

子进程工作PID=7077,PPID=7072

 

规则分析3

switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[1]);		char message[40001];		int num = read(fd[0], message, 4001);		printf("子进程读入的数据长度是=%d\n", num);		num = read(fd[0], message, 4000);		printf("子进程再次读入的数据长度是=%d", num);	    close(fd[0]);		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[0]);		const long int writesize = 4000;		char writeMsg[writesize];		int i;		for (i = 0; i < writesize; i++) {			writeMsg[i] = 'a';		}		int writenum = write(fd[1], writeMsg, strlen(writeMsg));		printf("父进程写入的数据长度是=%d\n", writenum);		close(fd[1]);	//	wait(NULL);		break;	}

[root@ Release30$] ps -C processcomm -o pid,ppid,stat,cmd

  PID PPID STAT CMD

=>读写进程都已退出

 控制台输出

父进程工作PID=8004,PPID=2488

父进程写入的数据长度是=4001

子进程工作PID=8009,PPID=1

子进程读入的数据长度是=4001

子进程再次读入的数据长度是=0

规则分析4

switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());		char message[40001];		int num = read(fd[0], message, 4001);		printf("子进程读入的数据长度是=%d", num);		num = read(fd[0], message, 4000);		printf("子进程再次读入的数据长度是=%d", num);		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[0]);		const long int writesize = 4000;		char writeMsg[writesize];		int i;		for (i = 0; i < writesize; i++) {			writeMsg[i] = 'a';		}		int writenum = write(fd[1], writeMsg, strlen(writeMsg));		printf("父进程写入的数据长度是=%d\n", writenum);		close(fd[1]);		break;	}

[root@ Release29$] ps -C processcomm -o pid,ppid,stat,cmd

  PID PPID STAT CMD

 7916    1 S   /root/workspace/processcomm/Release/processcomm

=>读进程阻塞

 

控制台输出:

父进程工作PID=7914,PPID=2488

父进程写入的数据长度是=4001

子进程工作PID=7916,PPID=1

规则分析5

switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());			close(fd[1]);		char message[65535];		int num = read(fd[0], message, 65535);		printf("子进程读入的数据长度是=%d", num);	close(fd[0]);		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[0]);		const long int writesize = 80000;		char writeMsg[writesize];		int i;		for (i = 0; i < writesize; i++) {			writeMsg[i] = 'a';		}		int writenum = write(fd[1], writeMsg, strlen(writeMsg));		printf("父进程写入的数据长度是=%d\n", writenum);		close(fd[1]);		wait(NULL);		break;	}

[root@ Release25$] ps -C processcomm -o pid,ppid,stat,cmd

  PID PPID STAT CMD

=>所有进程都以退出

 

控制台输出

父进程工作PID=7776,PPID=2488

子进程工作PID=7778,PPID=7776

子进程读入的数据长度是=65535

 

规则分析6

switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		const long int writesize=80000;		char writeMsg[writesize];		int i;		for(i=0;i

父进程工作PID=7309,PPID=2488

子进程工作PID=7314,PPID=7309

 

[root@ Release24$] ps -C processcomm -o pid,ppid,stat,cmd

  PID PPID STAT CMD

7309 2488 S   /root/workspace/processcomm/Release/processcomm

 7314 7309 Z    [processcomm]<defunct>

管道代码举例

1.   当发送信息小于管道最大长度

#include
#include
#include
#include
#include
#include
int main() { int fd[2]; pid_t cid; if (pipe(fd) == -1) { perror("管道创建失败!"); exit(1); } cid = fork(); switch (cid) { case -1: perror("子进程创建失败"); exit(2); break; case 0: printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid()); close(fd[1]); char message[1000]; int num; do { num = read(fd[0], message, 1000); printf("子进程读入的数据长度是=%d\n", num); } while (num != 0); close(fd[0]); break; default: printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid()); close(fd[0]); const long int writesize = 37; char writeMsg[writesize]; int i; for (i = 0; i < writesize-1; i++) { writeMsg[i] = 'a'; } writeMsg[writesize-1]='\0'; int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1); printf("父进程写入的数据长度是=%d\n", writenum); close(fd[1]); break; } return 0;}

2.   当发送信息大于管道最大长度

此例子主要应该规则6,当发送信息大于管道长度时且写进程在未全部将新数据写入管道中,写进程处于阻塞状态,直到所有数据写入管道

int main() {	int fd[2];	pid_t cid;	if (pipe(fd) == -1) {		perror("管道创建失败!");		exit(1);	}	cid = fork();	switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[1]);		char message[1000];		int num;		do {			num = read(fd[0], message, 1000);			printf("子进程读入的数据长度是=%d\n", num);		}while(num!=0);		close(fd[0]);		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		const long int writesize = 80000;		char writeMsg[writesize];		int i;		for (i = 0; i < writesize-1; i++) {			writeMsg[i] = 'a';		}		writeMsg[writesize-1]='\0';		int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1);		printf("父进程写入的数据长度是=%d\n", writenum);		close(fd[0]);		close(fd[1]);		break;	}	return 0;}

3.   写进程多次写入

此例应用规则6,防止多次写入,写入数据长度管道最大长度

int main() {	int fd[2];	pid_t cid;	if (pipe(fd) == -1) {		perror("管道创建失败!");		exit(1);	}	cid = fork();	switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[1]);		char message[1000];		int num;		do {			num = read(fd[0], message, 1000);			if (num > 0) {				printf("子进程读入的数据长度是=%d %s\n", num, message);			}		} while (num != 0);		close(fd[0]);		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		const long int writesize = 10;		char writeMsg[writesize];		int i;		for (i = 0; i < writesize - 1; i++) {			writeMsg[i] = 'a';		}		writeMsg[writesize - 1] = '\0';		int writenum = write(fd[1], writeMsg, strlen(writeMsg));		printf("父进程写入的数据长度是=%d\n", writenum);		char *newmsg = "helloworld";		writenum = write(fd[1], newmsg, strlen(newmsg) + 1);		printf("父进程再次写入的数据长度是=%d\n", writenum);		close(fd[0]);		close(fd[1]);		break;	}	return 0;}

4.   兄弟间的管道通讯

int main() {	int fd[2];	pid_t cid, did;	if (pipe(fd) == -1) {		perror("管道创建失败!");		exit(1);	}	cid = fork();	switch (cid) {	case -1:		perror("兄进程创建失败");		exit(2);		break;	case 0:		printf("兄进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[1]);		char message[1000];		int num;		do {			num = read(fd[0], message, 1000);			if (num > 0) {				printf("兄进程读入的数据长度是=%d,%s\n", num, message);			}		} while (num != 0);		close(fd[0]);		break;	default:		did = fork();		if (did == 0) {			printf("弟进程工作PID=%d,PPID=%d\n", getpid(), getppid());			const long int writesize = 10;			char writeMsgs[writesize];			int i;			for (i = 0; i < writesize - 1; i++) {				writeMsgs[i] = 'a';			}			writeMsgs[writesize - 1] = '\0';			int writenum = write(fd[1], writeMsgs, strlen(writeMsgs) + 1);			printf("弟进程写入的数据长度是=%d\n", writenum);			close(fd[0]);			close(fd[1]);		} else if (did == -1) {			perror("弟进程创建失败!");			exit(3);		}		break;	}	return 0;}

5.   父子双通道管道通讯

int main() {	int fd[2], backfd[2];	pid_t cid;	if (pipe(fd) == -1) {		perror("管道创建失败!");		exit(1);	}	if (pipe(backfd) == -1) {		perror("管道创建失败!");		exit(2);	}	cid = fork();	switch (cid) {	case -1:		perror("子进程创建失败");		exit(2);		break;	case 0:		printf("子进程工作PID=%d,PPID=%d\n", getpid(), getppid());		close(fd[1]);		char message[10000];		int num;		do {			num = read(fd[0], message, 10000);			printf("子进程读入的数据长度是=%d\n", num);		} while (num != 0);		close(fd[0]);		close(backfd[0]);		char *msg1 = "消息返回成功啊!";		write(backfd[1], msg1, strlen(msg1) + 1);		close(backfd[1]);		break;	default:		printf("父进程工作PID=%d,PPID=%d\n", getpid(), getppid());		const long int writesize = 80000;		char writeMsg[writesize];		int i;		for (i = 0; i < writesize - 1; i++) {			writeMsg[i] = 'a';		}		writeMsg[writesize - 1] = '\0';		int writenum = write(fd[1], writeMsg, strlen(writeMsg) + 1);		printf("父进程写入的数据长度是=%d\n", writenum);		close(fd[0]);		close(fd[1]);		close(backfd[1]);		char msg2[1000];		int num1 = read(backfd[0], msg2, 1000);		printf("返回消息是:%s", msg2);		close(backfd[0]);		break;	}	return 0;}

转载地址:http://adumi.baihongyu.com/

你可能感兴趣的文章
MySQL必知必会 -- 了解SQL和MySQL
查看>>
MySQL必知必会 -- 使用MySQL
查看>>
MySQL必知必会 -- 数据检索
查看>>
MySQL必知必会 -- 排序检索数据 ORDER BY
查看>>
MySQL必知必会 -- 数据过滤
查看>>
POJ 3087 解题报告
查看>>
POJ 2536 解题报告
查看>>
POJ 1154 解题报告
查看>>
POJ 1661 解题报告
查看>>
POJ 1101 解题报告
查看>>
ACM POJ catalogues[转载]
查看>>
ACM经历总结[转载]
查看>>
C/C++文件操作[转载]
查看>>
专业计划
查看>>
小米笔试:最大子数组乘积
查看>>
常见的排序算法
查看>>
5.PyTorch实现逻辑回归(二分类)
查看>>
6.PyTorch实现逻辑回归(多分类)
查看>>
8.Pytorch实现5层全连接结构的MNIST(手写数字识别)
查看>>
9.PyTorch实现MNIST(手写数字识别)(2卷积1全连接)
查看>>