进程间通信IPC

让每个进程拥有独立进空间的好处:
1、对于编程人员来说,系统更容易捕获随意的内存读取和写入操作
2、对于用户来说,操作系统将变得更加健壮,因为一个应用程序无法破坏另一个进程或操作系统的运行(防止被攻击)
独立进程空间的缺点:
1、多任务实现开销较大
2、编写能够与其它进程进行通信,或者能够对其它进程进行操作的应用程序要困难的多

狭义上的真正的进程间通信:管道、信号、消息队列、共享内存、信息量、套接字

管道

无名管道 和 有名管道
**无名管道:**只适合在父子进程之间通信
内核开辟一个管道,通信的进程通过共享这个管道,从而实现通信

int pipe(int pipedf[2])

头文件 #include <unistd.h>
参数:缓存地址,缓存用于存放读写管道的文件描述符。从这个参数的样子可以看出,这个缓存就是一个拥有两个元素的int型数组。

        1)元素[0]:里面放的是读管道的读文件描述符
        2)元素[1]:里面放的是写管道的写文件描述符。
        
    特别需要注意的是,这里的读和写文件描述符,是两个不同的文件描述符。

在这里插入图片描述

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>

int main()
{
	pid_t pid;

	int fd[2];

	if(pipe(fd)<0)
	{
		perror("pipe error!");
		exit(1);
	}

	char buffer [100];

	pid=fork();
	if(pid<0)
	{
		perror("fork error!");
		exit(1);
	}
	if(pid==0)
	{
		while(1)
		{
			close(fd[1]);
			read(fd[0],buffer,sizeof(buffer));
			printf("recv:%s\n",buffer);
			memset(buffer,0,sizeof(buffer));
			sleep(1);
		}

	}
	else if(pid>0)
	{
		while(1)
		{
			close(fd[0]);
			memset(buffer,0,sizeof(buffer));
			scanf("%s",buffer);
			write(fd[1],buffer,strlen(buffer));
		}

	}
	return 0;
}

无名管道特点:
1、会发生阻塞:读管道时,如果没有数据读操作会休眠(阻塞),写数据时,缓冲区写满会休眠(阻塞)
2、管道只允许具有血缘关系的进程间通信,如父子进程间的通信
3、管道只允许单项通信(通过以下方式可以实现双向)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>

int main()
{
	pid_t pid;

	int fd[2];
	int fd1[2];

	if(pipe(fd)<0)
	{
		perror("pipe error!");
		exit(1);
	}

	if(pipe(fd1)<0)
	{
		perror("pipe1 error!");
		exit(1);
	}

	char buffer[100];

	pid=fork();
	if(pid<0)
	{
		perror("fork error!");
		exit(1);
	}
	if(pid==0)
	{
		while(1)
		{
			close(fd1[0]);
			close(fd[1]);
			read(fd[0],buffer,sizeof(buffer));
			printf("recv:%s\n",buffer);
			write(fd1[1],buffer,strlen(buffer));
			memset(buffer,0,sizeof(buffer));
			sleep(1);
		}

	}
	else if(pid>0)
	{
		while(1)
		{
			close(fd1[1]);
			close(fd[0]);
			memset(buffer,0,sizeof(buffer));
			scanf("%s",buffer);
			write(fd[1],buffer,strlen(buffer));
			sleep(1);
			memset(buffer,0,sizeof(buffer));
			read(fd1[0],buffer,sizeof(buffer));
			printf("father recv:%s\n",buffer);
		}

	}
	return 0;
}

请添加图片描述
有名管道:可以提供任意两个进程之间的通信
int mkfifo(const char *pathname, mode_t mode);

 (1)功能
    创建有名管道文件,创建好后便可使用open打开。
 
    如果是创建普通文件的话,我们可以使用open的O_CREAT选项来创建,比如:
     open("./file", O_RDWR|O_CREAT, 0664);
    
    但是对于“有名管道”这种特殊文件,这里只能使用mkfifo函数来创建。
 (2)参数
    1)pathname:被创建管道文件的文件路径名。
    
    2)mode:指定被创建时原始权限,一般为0664(110110100),必须包含读写权限。
     
 (3)返回值:成功返回0,失败则返回-1,并且errno被设置。 

int mkfifo(const char*pathname,mode_t mode)
第一个参数:被创建管道文件的文件路径名
第二个参数:指定被创建时原始权限,一般为0664,必须包含读写权限
返回值:成功返回0,失败返回-1,并且errno被设置

mkfifo1.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#include<unistd.h>
#include<errno.h>


int main()
{
	pid_t pid;
	
	int ret;

  	char buffer[100];

	if((ret=mkfifo("./file",0644))<0)
	{
		if(ret==-1&&errno==EEXIST)
		{
			
		}
		else
		{
			perror("make mkfifo error!");
			exit(1);
		}
	}

	//pid=fork();


/*	if(pid<0)
	{
		perror("error");
		exit(1);
	}
	if(pid==0)
	{*/
		int fd=open("./file",O_RDONLY);
		while(1)
		{
			memset(buffer,0,sizeof(buffer));
			read(fd,buffer,sizeof(buffer));
			printf("recv:%s\n",buffer);
			sleep(2);
		}
/*
	}
	else if(pid>0)
	{
		int fd=open("./mkfifo",O_WRONLY);
		while(1)
		{
			memset(buffer,0,sizeof(buffer));
			scanf("%s",buffer);
			write(fd,buffer,strlen(buffer));
		}

	}*/
	return 0;
}


mkfifo2.c

#include<stdio.h>

#include<stdlib.h>
#include<string.h>

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#include<unistd.h>
#include<errno.h>


int main()
{
	pid_t pid;
	int ret;

  	char buffer[100];
  	
  		if((ret=mkfifo("./file",0644))<0)
	{
		if(ret==-1&&errno==EEXIST)
		{
			
		}
		else
		{
			perror("make mkfifo error!");
			exit(1);
		}
	}

/*	if(mkfifo("./file",0644)<0)
	{
		perror("make mkfifo error!");
		exit(1);
	}*/

/*	pid=fork();


	if(pid<0)
	{
		perror("error");
		exit(1);
	}
	if(pid==0)
	{
		int fd=open("./file",O_RDONLY);
		while(1)
		{
			memset(buffer,0,sizeof(buffer));
			read(fd,buffer,sizeof(buffer));
			printf("recv:%s\n",buffer);
			sleep(2);
		}

	}
	else if(pid>0)
	{*/
		int fd=open("./file",O_WRONLY);
		while(1)
		{
			memset(buffer,0,sizeof(buffer));
			scanf("%s",buffer);
			write(fd,buffer,strlen(buffer));
		}

//	}
	return 0;
}


请添加图片描述
注意事项:
1、有名管道这种特殊文件,稚嫩用mkfifo函数创建
2、为了保证管道一定被创建,最好是两个进程都包含创建管道的代码,谁先运行就谁先创建,后运行的发现管道已经创建好了,那就直接open打开使用
3、不能以O_RDWR模式打开命名管道FIFO文件,否则其行为是未定义的,管道是单向的,不能同时读写

管道的最大特点:发送的是无格式的数据

消息队列

分类:System V的消息队列 Posix消息队列
区别:对Posix消息队列的读总是返回最高优先级的最早消息,对System V
消息队列的读则可以返回任意指定优先级的消息

组成:1、消息编号:识别消息用
2、消息正文:真正的信息内容

                  struct msgbuf
                  {
                          long mtype;         /* 放消息编号,必须> 0 */
                          char mtext[msgsz];  /* 消息内容(消息正文) */
                  };

不会自动删除,重启时删除

使用msgget函数创建,返回唯一标识消息队列的标识符
int msgget(key_t key,int msgflg);
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
key 有三种方式:
最多使用:使用ftok函数来动态生成key

                      key_t ftok(const char *pathname, int proj_id);

                       ftok通过指定路径名和一个整形数,就可以计算并返回一个唯一对应的key值,
                     只要路径名和整形数不变,所对应的key值就唯一不变的。         
                       不过由于ftok只会使用整形数(proj_id)的低8位,因此我们往往会指定为一个ASCII码值,
                     因为ASCII码值刚好是8位的整形数。
                       
             
                  int msgget(key_t key, int msgflg);
                · msgflg
                     指定创建时的原始权限,比如0664
                     创建一个新的消息队列时,除了原始权限,还需要指定IPC_CREAT选项。
                  
                     msgid = msgget(key, 0664|IPC_CREAT);
                     
                       如果key值没有对应任何消息队列,就会创建一个新的消息队列,此时就会用到msgflg参数,
                     但是如果key已经对应了某个早已存在消息队列,就直接返回这个已存在消息队列的ID(标识符),
                     此时不会用到msgflg参数

在这里插入图片描述
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
用于读出消息队列的数据
1)函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

           (a)功能:发送消息到消息队列上。
                  说白了就是将消息挂到消息队列上。
           
           (b)返回值
                · 成功:返回0,
                · 失败:返回-1,errno被设置
           
           (c)参数
                · msqid:消息队列的标识符。
                · msgp:存放消息的缓存的地址,类型struct msgbuf类型
                     这个缓存就是一个消息包(存放消息的结构体变量)。
                     
                  struct msgbuf
                  {
                          long mtype;         /* 放消息编号,必须 > 0 */
                          char mtext[msgsz];  /* 消息内容(消息正文) */
                  };        
                  
                · msgsz:消息正文大大小。
                       
                · msgflg:
                  - 0:阻塞发送消息
                     也就是说,如果没有发送成功的话,该函数会一直阻塞等,直到发送成功为止。
                       
                       
                  - IPC_NOWAIT:非阻塞方式发送消息,不管发送成功与否,函数都将返回
                       也就是说,发送不成功的的话,函数不会阻塞。

函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

           (a)功能:接收消息
                  说白了就是从消息队列中取出别人所放的某个编号的消息。

                  
           (b)返回值
                成功:返回消息正文的字节数
                失败:返回-1,errno被设置
                
                
           (c)参数 
                · msqid:消息队列的标识符。
                · msgp:缓存地址,缓存用于存放所接收的消息
                  
                  类型还是struct msgbuf:
                  struct msgbuf
                  {
                          long mtype;         /* 存放消息编号*/
                          char mtext[msgsz];  /*存放 消息正文内容 */
                  };          
                  
                  
                · msgsz:消息正文的大小
                  
                · msgtyp:你要接收消息的编号
                  
                · int msgflg:
                  - 0:阻塞接收消息
                     也就是说如果没有消息时,接收回阻塞(休眠)。
                  
                  - IPC_NOWAIT:非阻塞接收消息
                     也就是说没有消息时,该函数不阻塞
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<sys/types.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>

struct msgbuf
{
	long id;
	char msg[1024];

};

int main()
{
	int msgid;
	open("./a",O_CREAT|O_RDWR);
	
	key_t key=ftok("./a",'k');

	if((msgid=msgget(key,0644|IPC_CREAT))<0)
	{
		perror("creat msg queue error!");
		exit(1);
	}

	pid_t pid;

	pid=fork();

	if(pid<0)
	{
		exit(1);
	}

	if(pid==0)
	{//msgid
		struct msgbuf *p_msg=(struct msgbuf*)malloc(sizeof(struct msgbuf));
		while(1)
		{
			memset(p_msg,0,sizeof(struct msgbuf));

			msgrcv(msgid,p_msg,sizeof(struct msgbuf),4,0);

			printf("recv:%s\n",p_msg->msg);

			sleep(1);
		}

	}

	else if(pid>0)
	{//msgid
		struct msgbuf *p_msg;
 		
		int i=0;

		while(1)
		{
			p_msg=(struct msgbuf*)malloc(sizeof(struct msgbuf));
			memset(p_msg,0,sizeof(struct msgbuf));

			scanf("%s",p_msg->msg);
			p_msg->id=i;
			i=i+1;

			msgsnd(msgid,p_msg,sizeof(struct msgbuf),0);

		}
	}

	return 0;
}

请添加图片描述
特点:
传送有格式的消息流
多进程网状交叉通信时,消息队列是上上之选
能实现大规模数据的通信

msg2.c


#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<sys/types.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>

struct msgbuf
{
	long id;
	char msg[1024];

};

int main()
{
	int msgid;
	open("./a",O_CREAT|O_RDWR);
	
	key_t key=ftok("./a",'k');

	if((msgid=msgget(key,0644|IPC_CREAT))<0)
	{
		perror("creat msg queue error!");
		exit(1);
	}


		struct msgbuf *p_msg=(struct msgbuf*)malloc(sizeof(struct msgbuf));
		while(1)
		{
			memset(p_msg,0,sizeof(struct msgbuf));

			msgrcv(msgid,p_msg,sizeof(struct msgbuf),4,0);

			printf("recv:%s\n",p_msg->msg);

			sleep(1);
		}




	return 0;
}

msg3.c


#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include<sys/types.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>

struct msgbuf
{
	long id;
	char msg[1024];

};

int main()
{
	int msgid;
	open("./a",O_CREAT|O_RDWR);
	
	key_t key=ftok("./a",'k');

	if((msgid=msgget(key,0644|IPC_CREAT))<0)
	{
		perror("creat msg queue error!");
		exit(1);
	}


		struct msgbuf *p_msg;
 		
		int i=0;

		while(1)
		{
			p_msg=(struct msgbuf*)malloc(sizeof(struct msgbuf));
			memset(p_msg,0,sizeof(struct msgbuf));

			scanf("%s",p_msg->msg);
			p_msg->id=i;
			i=i+1;

			msgsnd(msgid,p_msg,sizeof(struct msgbuf),0);

		}


	return 0;
}

请添加图片描述

信号量

在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/shm.h>
#include<signal.h>
#include<errno.h>
#include<unistd.h>

#define MAX_SIZE 1024

char *addr;
int shmid;

void my_exit(int signal)
{
	shmdt(addr);
	shmctl(shmid,IPC_RMID,0);
}

int main()
{
	signal(SIGINT,my_exit);

	char buffer[MAX_SIZE];

	if(open("./shm",O_CREAT|O_RDWR)<0)
	{
		perror("openshm error!");
		exit(1);
	}
	key_t shm_key=ftok("./shm",'b');

	if(open("./sem",O_CREAT|O_RDWR)<0)
	{
		perror("opensem error!");
		exit(1);
	}

	key_t sem_key=ftok("./sem",'c');

	shmid=shmget(shm_key,MAX_SIZE,0644|IPC_CREAT);

	int semid=semget(sem_key,1,0644|IPC_CREAT);

	semctl(semid,0,1,SETVAL,1);

	if(shmid==-1)
	{
		perror("shm get error!");
		exit(1);
	}

	pid_t pid=fork();

	if(pid<0)
	{
		perror("fork error!");
		exit(1);
	}

	if(pid==0)
	{
		sleep(1);
		addr=(char*)shmat(shmid,NULL,0);
		
		struct sembuf sem_buf;

		sem_buf.sem_num=0;

		sem_buf.sem_flg=SEM_UNDO;

		while(1)
		{
			sem_buf.sem_op=-1;
			semop(semid,&sem_buf,1);

			memset(buffer,0,sizeof(buffer));
			if(strlen(addr)!=0)
			{
				strcpy(buffer,addr);
				printf("recv:%s\n",buffer);
				memset(addr,0,MAX_SIZE);
			}
	//		sleep(2);

			sem_buf.sem_op=1;
			semop(semid,&sem_buf,1);

			sleep(2);
		}
	}
	else if(pid>0)
	{	
		addr=(char*)shmat(shmid,NULL,0);

		struct sembuf sem_buf;

		sem_buf.sem_num=0;
		sem_buf.sem_flg=SEM_UNDO;
		while(1)
		{
			sem_buf.sem_op=-1;
			semop(semid,&sem_buf,1);
			memset(buffer,0,sizeof(buffer));
			scanf("%s",buffer);
			strcpy(addr,buffer);
			sem_buf.sem_op=1;
			semop(semid,&sem_buf,1);
			sleep(2);
		}
	}
	return 0;
}

信号

62个信号
请添加图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

&*Savior

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

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

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

打赏作者

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

抵扣说明:

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

余额充值