day6--进程间的通信

进程间的通信

概念:进程间通信就是进程和进程之间交换信息

常用通信方式

无名管道(pipe)

有名管道 (fifo)

信号(signal)

共享内存(mmap)

套接字(socket)--主流的一个通信方式,后续网络专栏会详细介绍

过时的IPC通信方式

System V IPC

共享内存(share memory)

消息队列(message queue)

信号灯集(semaphore set)

无名管道

int pipe(int pfd[2]); //成功:0;失败:-1,设置errno

pfd[0] 为读操作

pfd[1] 为写操作

注:

        1.若父/子进程使用读操作,其他的进程就不使用读,写操作也如此

        2.管道写端被全部关闭,read返回0

        3. 管道读端被全部关闭,进程异常终止

coding

//无名管道的创建
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	int pfd[2];	//无名管道函数参数--[0]表示读操作 [1]表示写操作
	int ret;
	char buf[20]={0};
	pid_t pid;

	ret=pipe(pfd);	//创建无名管道的函数--成功返回0
	if(ret<0){
		perror("pipe");
		return 0;
	}

	pid=fork();
	if(pid<0){	//子进程创建失败
		perror("fork");
		return 0;
	}
	else if(pid==0){	//子进程
		//close(pfd[0]);
		while(1){
			strcpy(buf,"hello WMGD!\n");
			write(pfd[1],buf,strlen(buf));	//子进程写入
			sleep(1);
		}
	}
	else{	//父进程
		//close(pfd[1]);
		while(1){
			ret=read(pfd[0],buf,20);	//父进程读出
			if(ret>0)
				printf("father read:%s",buf);
		}
	}
	return 0;
}

有名管道

特点:

        1.有名管道可以使非亲缘的两个进程互相通信

        2.通过路径名来操作,在文件系统中可见,但内容存放在内存中

        3.文件IO来操作有名管道

        4.遵循先进先出规则

        5.不支持leek操作

        6.单工读写

创建管道

#include <sys/types.h>

#include <sys/stat.h>

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

open(const char *path, O_RDONLY);        //阻塞只读方式

open(const char *path, O_WRONLY);        //阻塞只写方式

open(const char *path, O_RDONLY | O_NONBLOCK);        //非阻塞只读方式

open(const char *path, O_WRONLY | O_NONBLOCK);        //非阻塞只写方式

coding

//写部分
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, const char *argv[])
{
	int ret,fd;
	char buf[32];
	ret=mkfifo("/myfifo",0666);
	if(ret<0){
		perror("mkfifo");
		//return 0;
	}
	fd=open("/myfifo",O_WRONLY);
	if(fd<0){
		perror("open");
		return 0;
	}
	while(1){
		fgets(buf,32,stdin);	//标准输入
		write(fd,buf,strlen(buf));//写入文件中
	}
	return 0;
}


//读部分
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, const char *argv[])
{
	int ret,fd;
	char buf[32];
	memset(buf,0,32);
	fd=open("/myfifo",O_RDONLY);
	if(fd<0){
		perror("open");
		return 0;
	}
	while(1){
		ret=read(fd,buf,32);
		if(ret>0){
			printf("read fifo=%s\n",buf);
		}else if(ret==0){
			exit(0);
		}
	}
	return 0;
}

共享内存--内存映射

查看共享内存命令ipcs

概念:

使一个磁盘文件与内存中的一个缓冲区相映射,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write

函数定义

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);       

功能:创建共享内存映射

函数返回值:成功返回创建的映射区首地址,失败返回MAP_FAILED( ((void *) -1) ),设置errno值

mmap()优点:

实现了用户空间和内核空间的高效交互方式

参数说明

addr:指定要映射的内存地址,一般设置为 NULL 让操作系统自动选择合适的内存地址。

length:必须>0,映射地址空间的字节数,它从被映射文件开头 offset 个字节开始算起。

prot:指定共享内存的访问权限。可取如下几个值的可选:PROT_READ(可读), PROT_WRITE(可写), PROT_EXEC(可执行), PROT_NONE(不可访问)。

flags:由以下几个常值指定:MAP_SHARED(共享的) MAP_PRIVATE(私有的), MAP_FIXED(表示必须使用 start 参数作为开始地址,如果失败不进行修正),其中,MAP_SHARED , MAP_PRIVATE必选其一,而 MAP_FIXED 则不推荐使用。MAP_ANONYMOUS(匿名映射,用于血缘关系进程间通信)

fd:表示要映射的文件句柄。如果匿名映射写-1

offset:表示映射文件的偏移量,一般设置为 0 表示从文件头部开始映射

注意事项

(1) 创建映射区的过程中隐含着一次对映射文件的读操作将文件内容读取到映射区

(2) 当MAP_SHARED时,要求:映射区的权限应 <=文件打开的权限(出于对映射区的保护),如果不满足报非法参数(Invalid argument)错误

          当MAP_PRIVATE时,mmap中的权限是对内存的限制,只需要文件有读权限即可,操作只在内存有效,不会写到物理磁盘,且不能在进程间共享

(3) 映射区的释放与文件关闭无关只要映射建立成功,文件可以立即关闭

(4) 用于映射的文件大小必须>0,当映射文件大小为0时,指定非0大小创建映射区,访问映射地址会报总线错误,指定0大小创建映射区,报非法参数错误(Invalid argument)

(5) 文件偏移量必须为0或者4K的整数倍(不是会报非法参数Invalid argument错误)

(6)映射大小可以大于文件大小,但只能访问文件page的内存地址,否则报总线错误 ,超出映射的内存大小报段错误

(7)mmap创建映射区出错概率非常高,一定要检查返回值,确保映射区建立成功再进行后续操作

mmap()映射的种类

1.基于文件的映射

2.匿名映射适用于具有亲缘关系的进程之间

释放内存映射

munmap函数

int munmap(void *addr, size_t length);

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

函数参数:

addr:调用mmap函数成功返回的映射区首地址

length:映射区大小(即:mmap函数的第二个参数)

coding

//内存映射--写
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, const char *argv[])
{
	void* addr;
	int fd;
	fd = open("test", O_RDWR);    //可读可写方式打开文件
	if(fd < 0) {
		perror("open");
		return 0;
	}

	addr = mmap(NULL,4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//可读可写方式映射4K内存空间
	if(addr == MAP_FAILED) {    //如果mmap函数返回值是MAP_FAILED,代表内存映射失败
		perror("mmap");
		return 0;
	}
	close(fd);    //内存映射成功后,可以关闭文件,照样可以读写
	int i = 0;
	while(i < 4096) {
		memcpy((addr+i), "a", 1);    //内存映射的写入
		i++;
		sleep(1);
	}
    munmap(addr,4096);    //释放内存映射空间
	return 0;
}




//内存映射--读
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(){

	void *addr;
	int fd;
	fd =open("test",O_RDWR);
	if(fd<0){
		perror("open");
		return 0;
	}

	addr = mmap(NULL,4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(addr == MAP_FAILED){
		perror("mmap");
		return 0;
	}
	close(fd);
	while(1){
		printf("read=%s\n",(char*)(addr));    //读出内存映射写入的内容
		sleep(1);
	}
    munmap(addr,4096);    //释放内存映射空间
}





//内存映射--匿名映射
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(){
	void* addr;
	addr = mmap(NULL,4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);    //匿名映射不需要文件,所以为-1
	if(addr == MAP_FAILED){
		perror("mmap");
		return 0;
	}

	pid_t pid;
	pid = fork();    //创建子进程

	if(pid<0){
		perror("fork");
		return 0;
	}
	else if(pid>0){
		memcpy(addr,"1234567890",10);    //父进程写
		wait(NULL);
	}else {
		sleep(1);
		printf("read father val=%s\n",(char *)addr);    //子进程读出
	}
	munmap(addr,4096);    //释放内存映射空间
}

System V -- 共享内存 -- 已过时

system V 共享内存使用步骤 -- 简略

1.创建/打开共享内存 -- key_t  ftok(const char *path,  int id);   int shmget(key_t key, int size, int shmfsg);

2.映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问  void  *shmat(int shmid, const void *shmaddr, int shmflg);

3.读写共享内存 

4.撤销共享内存映射   int  shmdt(void *shmaddr);

5.删除共享内存对象  int  shmctl(int shmid, int cmd, struct shmid_ds *buf);

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Cabbage

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值