Linux进程间通信

丶灬走出姿态 提交于 2020-01-28 04:49:13

进程间数据通信需要使用特殊手段,如信号量、队列、共享内存等,因为彼此之间获取不到全局变量。 线程间通信比较简单,直接使用全局变量就行。

一、队列

这篇CSDN博客讲述的队列通信验证是正确的。20191209

这篇文章讲得也很详细

1.创建新消息队列或取得已存在消息队列

原型:int msgget(key_t key, int msgflg);

参数:

     key:可以认为是一个端口号,也可以由函数ftok生成。

     msgflg:IPC_CREAT值,若没有该队列,则创建一个并返回新标识符;若已存在,则返回原标识符。

                IPC_EXCL值,若没有该队列,则返回-1;若已存在,则返回0

2.向队列读/写消息

msgrcv从队列中取用消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msgsnd将数据放到消息队列中:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

3.设置消息队列属性

int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );

4.例程

send端:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/ipc.h>


struct mymesg{
	long int mtype;
	char mtext[512];
};
int main()
{
    int i=0;
	int id = 0;
	struct mymesg ckxmsg;
	key_t key = ftok("/tmp",66);
	id = msgget(key,IPC_CREAT | 0666);
	if(id == -1)
	{
		printf("create msg error \n");
		return 0;
	}
	system( "ipcs -q" );                        /*查看系统IPC的状态*/
	while(1)
	{
		sleep(1);
		char msg[512];
		memset(msg,0,sizeof(msg));
		ckxmsg.mtype = 1;

		sprintf(ckxmsg.mtext,"%d",i++);
		printf("input message:%d\n",i);

		if(msgsnd(id,(void *)&ckxmsg,512,0) < 0)
		{
			printf("send msg error \n");
			return 0;
		}
	}
	return 0;
}

receive端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/msg.h>
#include<sys/ipc.h>
#include <unistd.h>

struct mymesg{
	long int mtype;
	char mtext[512];
};
int main()
{
	int id = 0;
	struct mymesg ckxmsg;
	key_t key = ftok("/tmp",66);
	id = msgget(key,0666|IPC_CREAT);
	if(id == -1)
	{
		printf("open msg error \n");
		return 0;
	}
	while(1)
	{
		if(msgrcv(id,(void *)&ckxmsg,512,1,1) < 0)
		{
			printf("receive msg error \n");
			return 0;
		}
		printf("data:%s\n",ckxmsg.mtext);
	}
	return 0;
}

实验发现问题:
每4个数据,收到一个数据。
在这里插入图片描述
研究中。。。

二、共享内存

共享内存的CSDN文章

1.生成键值

所需头文件:#include<sys/ipc.h>

函数原型 :key_t ftok(const char *path ,int id);

path为一个已存在的路径名

id为0~255之间的一个数值,代表项目ID,自己取

返回值:成功返回键值(相当于32位的int)。出错返回-1

例如:key_t key = ftok(/tmp”, 66);

2.创建共享存储空间

所需头文件:#include<sys/shm.h>

函数原型: int shmget(key_t key, size_t size,int flag);

key为ftok生成的键值

size为共享内存的长度,以字节为单位

flag为所需要的操作和权限,可以用来创建一个共享存储空间并返回一个标识符或者获得一个共享标识符。

flag的值为IPC_CREAT:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则直接返回共享存储标识符。

flag的值为 IPC_CREAT | IPC_EXCL:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则产生错误。

返回值:成功返回共享存储ID;出错返回-1

例如:int id = shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个整形共享存储标识符,如果key值已经存在有共享存储空间了,则出错返回-1int id = shmget(key,4096,IPC_CREAT|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个共享存储标识符,如果key值已经存在有共享存储空间了,则直接返回一个共享存储标识符。

3.获取第一个可用共享内存空间的地址

所需头文件:#include<sys/shm.h>

函数原型: void *shmat(int shmid, const void *addr, int flag);

shmid为shmget生成的共享存储标识符

addr指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置

flag为对数据的操作,如果指定为SHM_RDONLY则以只读方式连接此段,其他值为读写方式连接此段。

翻阅linux下shm.c文件得到#define SHM_RDONLY      010000  /* read-only access */

返回值:成功返回指向共享存储段的指针;错误返回-1(打印出指针的值为全F)

例如:char *addr  = shmat(id, NULL, 0);就会返回第一个可用的共享内存地址的指针的值给addr 

4.例程

command.c文件:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/shm.h>
#include "Command.h"
int sharememory(int ipc_size,int flag)
{
	int id;
	key_t key=ftok("/tmp",66);
	if(key < 0)
	{
		printf("get key error\n");
		return -1;
	}
	id = shmget(key,ipc_size,flag);
	if(id < 0)
	{
		printf("get id error\n");
		return -1;
	}
	return id;
}
 
int create_ipc(int ipc_size)
{
	return sharememory(ipc_size,IPC_CREAT|IPC_EXCL|0666);
}
int get_ipc(int ipc_size)
{
	return sharememory(ipc_size,IPC_CREAT|0666);
}
int destroy_sharememory(int id)
{
	return shmctl(id,IPC_RMID,NULL);
}

command.h文件:

#define NAME_LEN 20
typedef struct {
	char name[NAME_LEN];
	int age;
}ckx;
int sharememory(int ipc_size,int flag);
int create_ipc(int ipc_size);
int get_ipc(int ipc_size);

service.c文件:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdlib.h>
#include "Command.h"

int main()
{
	int i=0;
	ckx *p;
	int id=create_ipc(sizeof(ckx));
	if(id < 0)
	{
		printf("create sharememory error\n");
		return 0;
	}
	id = 0;
	int age=0;
	while(1)
	{
		sleep(1);
		id = get_ipc(sizeof(ckx));
		if(id < 0)
		{
			printf("get sharememory error\n");
			break;
		}
		p = (ckx *)shmat(id,NULL,0);
		if(p < 0)
		{
			printf("get sharememory addr error\n");
			p = NULL;
			break;
		}

		char name[NAME_LEN]="nihao";
		strcpy(p->name,name);
		p->age = age;
		printf("\nwrite: %d\n",age++);
		if(shmdt(p) == -1)
		{
			printf("shmdt error\n");
		}
		id = 0;
	}
	if(id !=0)
	{
		if(destroy_sharememory(id)<0)
		{
			printf("destroy error\n");
		}
	}
}

clint.c文件:

#include<stdio.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<stdlib.h>
#include"Command.h"

int main()
{
	int i=0;
	ckx *p;
	int id = 0;
	while(1)
	{
		sleep(1);
		id = get_ipc(sizeof(ckx));
		if(id < 0)
		{
			printf("get sharememory error\n");
			break;
		}
		p = (ckx *)shmat(id,NULL,0);
		if(p < 0)
		{
			printf("get sharememory addr error\n");
			p = NULL;
			break;
		}

		printf("\nname:%s \t age:%d\n",p->name,p->age);
		if(shmdt(p) == -1)
		{
			printf("shmdt error\n");
			break;
		}	
	}
	if(id !=0)
	{
		if(destroy_sharememory(id)<0)
		{
			printf("destroy error\n");
		}
	}
}

实验效果:
在这里插入图片描述
注:当程序第二次运行时,会失败。
使用ipcs -m查看系统的所有共享内存。
使用ipcs -m shmid删除上一次程序运行创建的共享内存。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!