基于消息队列和共享内存的进程间通信

引入

掌握基于消息队列和共享内存的进程间通信原理

实验项目

基于消息队列和共享内存的进程间通信

实验目的

1.加深对进程概念的理解,明确进程与程序的区别;进一步认识并发执行的实质。
2.掌握进程管理、进程通信。
3.Linux系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据。
4.本实验的目的是了解和熟悉:
5.Linux支持的消息通信机制及其使用方法
6.Linux系统的共享存储区的原理及使用方法。

实验预习

一、消息队列
1.消息队列概述:
消息队列是消息的链表,存放在内存中,由内核维护。
2.消息队列的特点:
消息队列允许一个或多个进程向它写入或者读取消息,并且每条消息都有类型;
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,编程时可以按消息的类型读取;
与无名管道、有名管道一样,从消息队列中读出消息,消息队列中数据会被删除。
同样消息队列中的消息是有格式的;
只有内核重启或人工删除时,该消息才会被删除,若不人工删除消息队列,消息队列会一直存在于内存中;
消息队列标识符,来标识消息队列。消息队列在整个;
在系统中是唯一的。
二、共享内存
共享内存允许两个或者多个进程共享给定的存储区域。
共享内存是进程间共享数据的一种最快的方法,一个进程向共享的内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
使用共享内存要注意的是多个进程之间对一个给定存储区访问的互斥。若一个进程正在向共享内存区写数据,则在它做完这一步操作前,别的进程不应当去读、写这些数据。

实验内容

一、消息队列的创建,消息的发送和接收
创建消息队列,调用msgget()、msgsnd()、msggrev()、msgctrl()等函数,进行两个进程之间消息的发送和接收。
二、共享存储的创建、附接和断接
创建共享内存,使用shmget()、shmat()、shmctl()、shmctl()等函数,实现两个进程之间的通讯。

实验设备

Windows PC
Linux Ubuntu

基本原理设计说明

一、设计原理:
为了便于操作和观察结果,用一个程序作为“引子”,先后通过fork()函数创建两个子进程,server和client,进行通信。
二、消息队列:
server端建立一个key为75的消息队列,等待其他进程发来的消息。当遇到类型为1的消息时,则作为结束信号,取消该队列,并退出Server。Server每收到一个消息后显示一句“(Server)received datetype (n) is:”;
Client端使用key为75的消息队列,先后发送类型为10到1的消息,然后退出。最后一个消息即server端需要的结束信号。Client每发送一条消息,显示一句“(Client)sent datetype (n) is: ”;
父进程在server和client均退出后结束。
三、共享内存:
server端建立一个key为75的消息队列,等待其他进程发来的消息。Server每收到一个消息后显示一句“(Server)received”;
Client端使用key为75的消息队列,接收共享内存中的消息。Client每发送一条消息,显示一句“(Client)sent”;
父进程在server和client均退出后结束。

实验步骤

一、消息队列

1.编写程序,使用系统调用fork()创建两个子进程server和client,父进程等待两个子进程结束后退出。

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int main(int argc ,char *argv[])
{

	pid_t pid;
	pid = fork();	
	if(pid <0)
	{
		printf("fork error\n");
	}
	if(pid ==0)
	{			
	}
	else
	{		
		pid_t pid;
		pid = fork();
		if(pid <0)
		{
			printf("fork error\n");
		}
		if(pid ==0)
		{	    
		}
		}else{
			wait(NULL);
			sleep(1);
			printf("Main process quit\n");	
		}	
	}	
	return 0;
}

2.创建消息队列的消息格式结构体。

typedef struct _msg
{
	long msgtype;
	char m[500];

}MSG;

3.在client端,创建key值为75的消息队列,循环发送10次初始值为“abcdefghij”的字符串,且每次发送完,指针后移一位以实现每次发送内容不同的效果,同时,每次发送消息的消息类型由10递减到1,当发送完消息类型为1的消息后,client端退出。

if(pid ==0)
	{
		int msgqid;
		int i = 0;
		msgqid = msgget(75,IPC_CREAT|0666);
		MSG msg;
		memset(msg.m,0,sizeof(msg.m));
		msg.msgtype = 10;
		char *a = "abcdefghij";
		for(;i < 11;i++)
		{
			strcpy(msg.m,a);
			sleep(1);
			msgsnd(msgqid,&msg,sizeof(msg.m),0);		
			printf("(Client)sent datetype %ld: %s\n",msg.msgtype,msg.m);
			msg.msgtype--;
			a++;
			if(msg.msgtype == 0 )
			{
				sleep(1);
				printf("Client sent over and shutdown now\n");
				exit(0);
			}
		}		
	}

4.在server端,创建key值为75的消息队列,实时接收来自消息队列的消息,接收的消息类型由10递减到1,当接收完消息类型为1的消息后,销毁消息队列,server端退出。

扫描二维码关注公众号,回复: 10723982 查看本文章
if(pid ==0)
		{
	    int msgqid;
		int type = 10;
		msgqid = msgget(75,IPC_CREAT|0666);
		MSG msg;
		while(1)
		{
			msgrcv(msgqid,&msg,sizeof(msg.m),type,0);	
			printf("\t\t\t\t\t(Server)receiveddatetype %d: %s\n",type,msg.m);
			type--;
			if(type == 0)
			{
				msgctl(msgqid,IPC_RMID,NULL);
				sleep(1);
				printf("Sever get type 1 date and shutdown \n");
				sleep(1);
				printf("message queue destroyed\n");
				sleep(2);
				exit(0);
			}
		}

5.运行效果如下:
在这里插入图片描述

二、共享内存

  1. 编写程序,使用系统调用fork()创建两个子进程server和client,父进程等待两个子进程结束后退出。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <fcntl.h>
#include <string.h>
#define BUF 2048
int main(int argc,char *argv[])
{
	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		perror("fork error\n");
	}
	if(pid == 0)
	{	
		
	}
	else{
	    pid_t pid;
		pid = fork();
		if(pid < 0)
		{
			perror("fork error\n");
         	}
		if(pid == 0)
		{
		
		}
		else{	
			wait(NULL);
			sleep(2);
			printf("Process quit\n");
		    }	
	    }
	return 0;
}
  1. 在client端,创建key值为75,大小为2048的,可读可写的共享内存,实现共享内存映射后,循环发送10次初始值为“5201314”的字符串,且每次发送完,指针后移一位以实现每次发送内容不同的效果,直到发送完内容为“4”的消息后,client端自然结束。
if(pid == 0)
	{	
		int shmid;
		int i = 0;
		char *a = "5201314";
		shmid = shmget(75,BUF,SHM_R|SHM_W|IPC_CREAT);
		char *shmadd;
		shmadd = shmat(shmid,NULL,0);
		bzero(shmadd,BUF);
		for(;i < 7;i++){
			sleep(1);
			bzero(shmadd,BUF);
			strcpy(shmadd,a);
			printf("(Client) sent: %s\n",shmadd);
			a++;
		     }
	}

3.在server端,在client端,创建key值为75,大小为2048的,可读可写的共享内存,实现共享内存映射后,实时接收共享内存中client端发送的消息,且当接收完内容为“4”的消息后,解除共享内存映射,销毁共享内存,并结束进程。

if(pid == 0)
		{
		int shmid;
		shmid = shmget(75,BUF,SHM_R|SHM_W|IPC_CREAT);
		char *shmadd;
		shmadd = shmat(shmid,NULL,0);
		bzero(shmadd,BUF);
		while(1){
				sleep(1);
				printf("\t\t\t\t(Server) received: %s\n",shmadd);
				if(*shmadd == '4')
				{
					exit(0);
				}
			}
		shmdt(shmadd);
		shmctl(shmid,IPC_RMID,NULL);
		}

4.运行效果如下:
在这里插入图片描述

分析体会

分析:此实验只要掌握了进程的创建与控制原理,消息队列的创建以及相关函数的调用,共享内存的创建以及相关函数调用等知识,根据各自的通信原理,通过一步接一步的操作即可完成。
体会:通过动手操作本次实验,认识到Linux应用程序设计确实是一门操作性极强的课程,动手操作是验证和掌握课本理论知识,加固自己对Ubuntu的认识了理解,更加熟练地对其进行操作的最佳方法,通过亲自操作,感受消息队列和共享内存相关的运行原理,收获颇多,为以后的学习打下了坚实的基础。

实验结果

随着测试结果的成功,进程的创建、控制,消息队列的创建与进程间通讯,共享内存的创建于进程间通讯,均运行成功,实现了实验目的,实验完美成功!

结束

此处用于笔记整理,内容仅供参考

发布了3 篇原创文章 · 获赞 0 · 访问量 22

猜你喜欢

转载自blog.csdn.net/qq_43711326/article/details/105453454