• Linux学习记录--匿名沟通渠道


    匿名沟通渠道


    管道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<unistd.h>
    #include<stdio.h>
    #include<string.h>
    #include<sys/types.h>
    #include<stdlib.h>
    #include<sys/wait.h>
    
    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
    ", getpid(), getppid());
    		break;
    	default:
    		printf("父进程工作PID=%d,PPID=%d
    ", 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
    ", writenum);
    		close(fd[1]);
    		wait(NULL);
    		break;
    	}
    

    控制台输出

    父进程工作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
    ", getpid(), getppid());
    		close(fd[1]);
    		char message[40001];
    		int num = read(fd[0], message, 4001);
    		printf("子进程读入的数据长度是=%d
    ", num);
    		num = read(fd[0], message, 4000);
    		printf("子进程再次读入的数据长度是=%d", num);
    	    close(fd[0]);
    		break;
    	default:
    		printf("父进程工作PID=%d,PPID=%d
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", getpid(), getppid());
    		break;
    	default:
    		printf("父进程工作PID=%d,PPID=%d
    ", getpid(), getppid());
    		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
    ", writenum);
    		wait(NULL);
    		break;
    	}
    

    父进程工作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<unistd.h>
    #include<stdio.h>
    #include<string.h>
    #include<sys/types.h>
    #include<stdlib.h>
    #include<sys/wait.h>
    
    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
    ", getpid(), getppid());
    		close(fd[1]);
    		char message[1000];
    		int num;
    		do {
    
    			num = read(fd[0], message, 1000);
    			printf("子进程读入的数据长度是=%d
    ", num);
    		} while (num != 0);
    
    		close(fd[0]);
    		break;
    	default:
    		printf("父进程工作PID=%d,PPID=%d
    ", 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]='';
    		int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1);
    		printf("父进程写入的数据长度是=%d
    ", 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
    ", getpid(), getppid());
    		close(fd[1]);
    		char message[1000];
    		int num;
    		do {
    			num = read(fd[0], message, 1000);
    			printf("子进程读入的数据长度是=%d
    ", num);
    		}while(num!=0);
    
    		close(fd[0]);
    		break;
    	default:
    		printf("父进程工作PID=%d,PPID=%d
    ", 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]='';
    		int writenum = write(fd[1], writeMsg, strlen(writeMsg)+1);
    		printf("父进程写入的数据长度是=%d
    ", 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
    ", getpid(), getppid());
    		close(fd[1]);
    		char message[1000];
    		int num;
    		do {
    			num = read(fd[0], message, 1000);
    			if (num > 0) {
    				printf("子进程读入的数据长度是=%d %s
    ", num, message);
    			}
    
    		} while (num != 0);
    
    		close(fd[0]);
    		break;
    	default:
    		printf("父进程工作PID=%d,PPID=%d
    ", 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] = '';
    		int writenum = write(fd[1], writeMsg, strlen(writeMsg));
    		printf("父进程写入的数据长度是=%d
    ", writenum);
    
    		char *newmsg = "helloworld";
    		writenum = write(fd[1], newmsg, strlen(newmsg) + 1);
    		printf("父进程再次写入的数据长度是=%d
    ", 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
    ", getpid(), getppid());
    		close(fd[1]);
    		char message[1000];
    		int num;
    		do {
    			num = read(fd[0], message, 1000);
    			if (num > 0) {
    				printf("兄进程读入的数据长度是=%d,%s
    ", num, message);
    			}
    
    		} while (num != 0);
    
    		close(fd[0]);
    		break;
    	default:
    		did = fork();
    		if (did == 0) {
    			printf("弟进程工作PID=%d,PPID=%d
    ", 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] = '';
    			int writenum = write(fd[1], writeMsgs, strlen(writeMsgs) + 1);
    			printf("弟进程写入的数据长度是=%d
    ", 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
    ", getpid(), getppid());
    		close(fd[1]);
    		char message[10000];
    		int num;
    
    		do {
    
    			num = read(fd[0], message, 10000);
    			printf("子进程读入的数据长度是=%d
    ", 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 ", 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] = ''; int writenum = write(fd[1], writeMsg, strlen(writeMsg) + 1); printf("父进程写入的数据长度是=%d ", 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; }



  • 相关阅读:
    七七四十九劫,九九八十一难
    Android中用layer-list编写阴影效果
    Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)
    Effective C++ 24,25
    windows系统port监听
    线程同步辅助类——Exchanger
    C/C++中constkeyword
    【COCOS2DX-游戏开发之三三】TMX边界控制与小窗体内预览TMX
    IDFA的值什么时候会发生改变
    hadoop(六)
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4564388.html
Copyright © 2020-2023  润新知