Linux系统学习:进程间的通信

一 分类

1.同一主机

(1)传统

无名管道;

有名管道;

信号。

(2)SystemV

共享内存;//这是效率最高的通信方式

消息队列;

信号量。//都是信号量的机制

2.不同主机

socket:分为本地socket(本地套接字)和不同主机socket(网络套接字)。

二 原理

每个进程都拥有独立的4G内存空间,但其中的内核(1G)空间是共享的,所有进程间的通信方式,本质上都是借助操作系统内核来完成的。

三 无名管道

就是在内核建立一个管道,无名管道本质上是一种特殊的文件,它不存在硬盘,而是在内核空间的内存中,因为在文件系统中没有名字,所以叫无名。

1.无名管道的创建

int pipe(int pipefd2);

参数:pipefd,用来存放管道两端的文件描述符,0是读端,1是写端

返回值:成功返回0,失败返回-1并且errno会被设置

2.管道的特点

1)管道的大小---64kb(65526个字节)

2)管道读写规则

读写端都存在,可以读写管道,但是如果管道是满的,写操作阻塞,如果管道是空的,读操作会阻塞;读端存在写端不存在,如果管道是空的,读操作直接返回;读端不存在写端存在,如果进行写操作,管道破裂(SIGPIPE --- 信号的作用 --结束进程 //broken pipe )。

3.管道中的数据

是一个数据流,读走了就没有了,遵循FIFO的方式

4.是一种特殊的文件,但是不能进行lseek操作(插队)

5.用在亲缘关系进程间通信

6.管道是一种半双工的通信

单工:数据的发送方和接收方是固定的eg:广播

半双工:同一时刻只能有一个方向的数据传输eg:对讲机

全双工:同时收同时发

无名管道实际上是单工的,但是可以实现半双工的效果。

创建管道进行读写:

cpp 复制代码
#include<stdio.h>
#include<unistd.h>

int main(int argc, const char *argv[])
{
	int fd[2];
	if(pipe(fd) < 0)
	{
		perror("pipe fail");
		return -1;
	}
	
	printf("fd[0] = %d fd[1] = %d\n",fd[0],fd[1]);

	char buf[]="abcdefg";
	int ret_w = write(fd[1],buf,sizeof(buf));
	int ret_r = read(fd[0],buf,sizeof(buf));
	
	printf("ret_w = %d ret_r = %d\n",ret_w,ret_r);

	return 0;
}

父进程写管道数据,子进程读管道数据:

cpp 复制代码
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, const char *argv[])
{
	int fd[2];
	if(pipe(fd) < 0)
	{
		perror("pipe fail");
		return -1;
	}

	pid_t pid = fork();
	if(pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	if(pid>0)
	{
		close(fd[0]);
		while(1)
		{
			char buf[1024];
			fgets(buf,sizeof(buf),stdin);
			write(fd[1],buf,sizeof(buf));
			if(strncmp(buf,"quit",4) == 0)
			{
				close(fd[1]);
				wait(NULL);
				exit(0);
			}
		}
	}else if(pid == 0)
	{
		close(fd[1]);
		while(1)
		{
			char buf[1024];
			read(fd[0],buf,sizeof(buf));
			printf("%s\n",buf);
			if(strncmp(buf,"quit",4)==0)
			{
				close(fd[0]);
				exit(0);
			}
		}
	}

	return 0;
}

父子进程双向通信

cpp 复制代码
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, const char *argv[])
{
	int fd[2];
	if(pipe(fd) < 0)
	{
		perror("pipe fail");
		return -1;
	}

	int fd1[2];
	if(pipe(fd1) < 0)
	{
		perror("pipe fail");
		return -1;
	}

	pid_t pid = fork();
	if(pid < 0)
	{
		perror("fork fail");
		return -1;
	}

	if(pid>0)
	{
		close(fd[0]);
		close(fd1[1]);
		while(1)
		{
			char buf[1024];
			printf("input 1 pipe:");
			fgets(buf,sizeof(buf),stdin);
			write(fd[1],buf,sizeof(buf));
			
			char buf1[1024];
			read(fd1[0],buf1,sizeof(buf1));
			printf("pipe 2 = %s\n",buf1);
			if(strncmp(buf,"quit",4) == 0 || strncmp(buf1,"quit",4) == 0)
			{
				close(fd1[0]);
				close(fd[1]);
				wait(NULL);
				exit(0);
			}
		}
	}else if(pid == 0)
	{
		close(fd[1]);
		close(fd1[0]);
		while(1)
		{
			char buf[1024];
			read(fd[0],buf,sizeof(buf));
			printf("pipe 1 = %s\n",buf);
			
			char buf1[1024];
			printf("input 2 pipe:");
			fgets(buf1,sizeof(buf1),stdin);
			write(fd1[1],buf1,sizeof(buf1));
			
			if(strncmp(buf,"quit",4)==0 || strncmp(buf1,"quit",4)==0)
			{
				close(fd[0]);
				close(fd1[1]);
				exit(0);
			}
		}
	}

	return 0;
}

四 有名管道

  1. 特点:

符合管道特性;有名管道也是一种特殊的文件,有名 --- 在文件系统有名字类似于普通文件的名字,使用时,可以当作普通文件进行操作但也不能lseek 定位

2.用途:任意进程间

3.创建

int mkfifo(const char *pathname, mode_t mode);

功能:创建有名管道文件

参数:pathname----管道文件名;mode---文件权限

返回值:成功 0,失败 -1 && errno被设置

有名管道进行通信时,需要进行打开操作 open,如果只有一端 以 只读或只写的方式打开 ,此时程序会阻塞在open操作 ,必须等待 另一端 以只写或只读的相对方式打开,阻塞才会解除,此时也表示有名管道文件 读端和写端都打开了。

4.卸载管道:

int unlink(const char *pathname);

功能:将指定的pathname管道文件卸载,同时从文件系统中删除。

参数: ptahtname 要卸载的有名管道

返回值:成功 0,失败 -1;

创建管道进行读写:

cpp 复制代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>

int main(int argc, const char *argv[])
{
	if(mkfifo("fifo",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	
	printf("mkfifo success\n");

	int fd = open("fifo",O_RDONLY);
	if(fd < 0)
	{
		perror("open fail");
		return -1;
	}
	while(1)
	{
		char buf[1024];
		read(fd,buf,sizeof(buf));

		printf("%s\n",buf);
		if(strncmp(buf,"quit",4)==0)
		{
			break;
		}
	}
	close(fd);
	unlink("fifo");
	return 0;
}
cpp 复制代码
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>

int main(int argc, const char *argv[])
{
	if(mkfifo("fifo",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	
	printf("mkfifo success\n");

	int fd = open("fifo",O_WRONLY);
	if(fd < 0)
	{
		perror("open fail");
		return -1;
	}
	while(1)
	{
		char buf[1024];
		printf("Input > ");
		fgets(buf,sizeof(buf),stdin);
		write(fd,buf,sizeof(buf));

		if(strncmp(buf,"quit",4)==0)
		{
			break;
		}
	}
	close(fd);
	unlink("fifo");
	return 0;
}

双向通信:两边同时收和发

cpp 复制代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>

int main(int argc, const char *argv[])
{
	if(mkfifo("fifo1",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	
	printf("mkfifo1 success\n");

	int fd1 = open("fifo1",O_RDONLY);
	if(fd1 < 0)
	{
		perror("open fail");
		return -1;
	}
	
	if(mkfifo("fifo2",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	
	printf("mkfifo1 success\n");

	int fd2 = open("fifo2",O_WRONLY);
	if(fd2 < 0)
	{
		perror("open fail");
		return -1;
	}

	pid_t pid = fork();

	if(pid > 0)
	{
		while(1)
		{
			sleep(1);
			char buf[1024];
			printf("2 fifo Input>");
			fgets(buf,sizeof(buf),stdin);
			write(fd2,buf,sizeof(buf));
			if(strncmp(buf,"quit",4)==0)
			{
				break;
			}
		}
	}else if(pid == 0)
	{
		while(1)
		{
			sleep(1);
			char buf[1024];
			read(fd1,buf,sizeof(buf));
			printf("1 fifo output = %s\n",buf);
			if(strncmp(buf,"quit",4)==0)
			{
				break;
			}
		}
	}

	close(fd1);
	close(fd2);
	unlink("fifo1");
	unlink("fifo2");
	return 0;
}
cpp 复制代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>

int main(int argc, const char *argv[])
{
	if(mkfifo("fifo1",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	
	printf("mkfifo1 success\n");

	int fd1 = open("fifo1",O_WRONLY);
	if(fd1 < 0)
	{
		perror("open fail");
		return -1;
	}
	
	if(mkfifo("fifo2",0666) < 0 && errno != EEXIST)
	{
		perror("mkfifo fail");
		return -1;
	}
	
	printf("mkfifo1 success\n");

	int fd2 = open("fifo2",O_RDONLY);
	if(fd2 < 0)
	{
		perror("open fail");
		return -1;
	}

	pid_t pid = fork();

	if(pid > 0)
	{
		while(1)
		{
			sleep(1);
			char buf[1024];
			printf("1 fifo input>");
			fgets(buf,sizeof(buf),stdin);
			write(fd1,buf,sizeof(buf));
			if(strncmp(buf,"quit",4)==0)
			{
				break;
			}
		}
	}else if(pid == 0)
	{
		while(1)
		{
			sleep(1);
			char buf[1024];
			read(fd2,buf,sizeof(buf));
			printf("2 fifo out %s\n",buf);
			if(strncmp(buf,"quit",4)==0)
			{
				break;
			}
		}
	}

	close(fd1);
	close(fd2);
	unlink("fifo1");
	unlink("fifo2");
	return 0;
}
相关推荐
艾莉丝努力练剑4 小时前
【AI接入大模型SDK】ChatSDK示例验证
人工智能·学习·面试·大模型·sdk
葡萄成熟时 !10 小时前
JAVA 常用API学习笔记
java·笔记·学习
别动我齐刘海11 小时前
机器人运动控制学习2——基础进阶
c++·人工智能·神经网络·学习·目标检测·机器学习·机器人
05664613 小时前
agent学习——流式响应与文本切分
网络·python·学习
for_ever_love__14 小时前
python基础语法学习: 面向对象的三大特性
开发语言·python·学习
Canmag 兴隆磁性16 小时前
C 系列充磁机
c语言·开发语言·学习·永磁材料·充磁·退磁
PC2005-cloud17 小时前
Go学习笔记:基本概念与项目结构——GOPATH、Go Modules 与常用命令
笔记·学习·golang
新手unity自用笔记18 小时前
unity基于Socket的网络学习
网络·网络协议·学习·unity·c#·游戏引擎
zyf10441618 小时前
暑期实践日志 Day32:完成第六章字幕添加,推进工作
学习·计算机网络·剪辑·暑期实践·课题任务