linux进程间通讯

发布于:2023-01-21 ⋅ 阅读:(419) ⋅ 点赞:(0)

1.进程间通讯

有名和无名管道

(1)有名管道

mkfifo

(2)无名管道:只能用于既具有亲缘关系的进程间通讯

pipe

(3)信号

在软件层次上的中断模拟

2.system V IPC 对象

ipcs:查看IPC对象

私有的共享内存,key为0,

所有的IPC对象,只能通过用户显式的进行删除,手动申请,手动释放

(1)共享内存

共享内存是所有进程间通信方式中效率最高的一种。

使用共享内存流程:🥶🥶🥶🥶🥶🥶🥶🥶

1.创建或者打开共享内存 --shmget()

2.映射共享内存 --shmat()

3.访问共享内存(读写)

4.取消映射 --shmdt()

5.删除共享内存 ---shmctl()

0.key值的获取

#include <sys/types.h>
#include <sys/ipc.h>

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

参数:
    pathname:任意路径
    proj_id:任意字符
    字符串与整数的低八位运算,生成的key值,只有相同的路径与字符才能生成一样的key值。
    eg:    key_t key=ftok(".",'s');

返回值:
    成功返回key值,失败返回-1

1.创建或者打开共享内存 --shmget()

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

参数:
    key:通过ftok得到,或者通过宏IPC_PRIVATE(创建私有的共享内存,只有亲缘进程可以使用)
    size:共享内存的大小
    shmflg:创建共享内存权限,一般填0664 | IPC_CREAT

返回值:
    成功,得到共享内存ID,失败返回-1
eg:
    int shmid = shmget(key,1024,IPC_CREAT | 0664)

2.映射共享内存 --shmat()

#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

参数:
    shmid:共享内存ID
    shmaddr:填NULL,表示系统自动分配
    shmflg:SHM_RDONLY    --只读
            0    --读写
        
返回值:
    成功返回映射地址,失败返回(void *)-1

3.访问共享内存(读写)

scanf("%d",(char *)addr);
fgets((char *)addr,1024,stdin);

put((char *)addr);

4.取消映射 --shmdt()

#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);

参数:
    要取消映射的地址;
返回值:
    成功返回0,失败返回-1

5.删除共享内存 ---shmctl()

#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数:
    shmid:共享内存的ID号
    cmd:操作共享内存的指令
    IPC_STAT:获取共享内存的信息,存于第三个参数,结构体指针
    IPC_SET:设置共享内存信息,通过第三个参数,结构体指针
    IPC_RMID:删除共享内存,第三个参数填NULL(连接数(映射数)为0的情况下才能删除)

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

练习:使用两个进程,一个进程向共享内存输入数据,另外一个内存输出数据

write:

/*===============================================
*   文件名称:shmget.c
*   创 建 者:     
*   创建日期:2022年08月11日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{ 
    key_t key=ftok(".",'p');//生成key值
    if(key<0)
    {
        perror("ftok");
        return -1;
    }
    int shmid = shmget(key,1024,0664 | IPC_CREAT);//生成共享空间,记录id
    if(shmid<0)
    {
        perror("shmget");
        return -1;
    }
    void  *addr =shmat(shmid,NULL,0);映射
    if(addr==(void *)-1)
    {
        perror("shmat");
        exit(-1);
    }
    
    
    //addr=(char *)addr;
    memset(addr,0,1024);	//清空缓存
    while(1)
    {
        scanf("%s",(char *)addr);	//键盘输入
        sleep(1);        
    }

    int ret = shmdt(addr);	//删除映射
    if(ret<0)
    {
        perror("shmdt");
        exit(-1);
    }
    
    int ret1=shmctl(shmid,IPC_RMID,NULL);//关闭共享内存
    if(ret1<0)
    {
        perror("shmctl");
        exit(-1);
    }

    return 0;
} 

 read:

/*===============================================
*   文件名称:shmget.c
*   创 建 者:     
*   创建日期:2022年08月11日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{ 
    key_t key=ftok(".",'p');//生成key值
    if(key<0)
    {
        perror("ftok");
        return -1;
    }
    int shmid = shmget(key,1024,0664 | IPC_CREAT);//创建共享内存
    if(shmid<0)
    {
        perror("shmget");
        return -1;
    }
    void  *addr =shmat(shmid,NULL,0);//映射
    if(addr==(void *)-1)
    {
        perror("shmat");
        exit(-1);
    }
    
    while(1)
    {        
        puts((char *)addr);//从共享内存输出
        sleep(1);
    }

    int ret = shmdt(addr);//取消映射
    if(ret<0)
    {
        perror("shmdt");
        exit(-1);
    }
    
    
    return 0;
} 

(2)消息队列

消息队列的使用流程

1.创建、打开消息队列 --msgget(0)

2.发送消息 --msgsnt()

3.接收消息 --msgrcv()

4.删除消息队列 --msgctl()

1.创建、打开消息队列 --msgget()

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

参数:
    key:通过ftok得到的key值,或者使用IPC_PRIVATE创建私有消息队列
     msgflg: 创建消息队列权限,一般填0664 | IPC_CREAT    
    
返回值:
成功返回消息队列ID,失败返回-1

eg:
    int msgid=msgget(IPC_PRIVATE,0664);//只能是创建,之前不会存在

2.发送消息 --msgsnt()

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数:
    msqid:消息队列ID
    msgp:与发送消息相关的结构体的首地址
    msgsz:消息结构体中,正文内容的大小(n)
    msgflg:发送消息的方式
填0--表示以阻塞方式发送消息
IPC_NOWAIT--不阻塞方式送

返回值:
    成功返回0,失败返回-1
        
用法:
      
#define LEN (sizeof(MSG)-sizeof(long) )//    第三个参数
        
 typedef struct msgbuf
 {
     long mtype;
     char mtext[64];//大小自己填
 }MSG;
     
MSG msg;//第二个参数
char buf[64]={0};
msg.mtype=100;
fgets(buf,64,stdin);
strcpy(msg.mtext,buf);


msgsnd(msgid,&msg,LEN,0);

    
    
    
自己封装结构体
struct msgbuf {
               long mtype;       /* message type, must be > 0 */
               char mtext[1];    /* message data */
           };

3.接收消息 --msgrcv()

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
    msqid:消息队列ID
    msgp:与接收消息相关的结构体的首地址
    msgsz:消息结构体中,正文内容的大小(n)
    msgtyp:接收的消息队列的类型,在结构体中定义    🎆🎉🎉🎉
    msgflg:发送消息的方式
填0--表示以阻塞方式接收消息
IPC_NOWAIT--不阻塞方式接收

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

#define LEN (sizeof(MSG)-sizeof(long) )//    第三个参数
        
 typedef struct msgbuf
 {
     long mtype;
     char mtext[64];//大小自己填
 }MSG;
     
MSG msg;//第二个参数
char buf[64]={0};
msg.mtype=100;
fgets(buf,64,stdin);
strcpy(msg.mtext,buf);


msgsnd(msgid,&msg,LEN,0);
        
自己封装结构体
struct msgbuf {
               long mtype;       /* message type, must be > 0 */
               char mtext[1];    /* message data */
           };

4.删除消息队列 --mesgctl()

#include <sys/msg.h>

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

参数:
    shmid:共享内存的ID号
    cmd:操作共享内存的指令
    IPC_STAT:获取共享内存的信息,存于第三个参数,结构体指针
    IPC_SET:设置共享内存信息,通过第三个参数,结构体指针
    IPC_RMID:删除共享内存,第三个参数填NULL(连接数(映射数)为0的情况下才能删除)

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

练习:使用两个进程,两个进程间互相收发信息

read:

/*===============================================
*   文件名称:read_msg.c
*   创 建 者:     
*   创建日期:2022年08月11日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

#define LEN (sizeof(MSG)-sizeof(long))
#define typeA 100
#define typeB 200

typedef struct msgbuf
{
	long mtype;
	char mtext[64];
}MSG;

int main(int argc, char *argv[])
{ 

	key_t key=ftok(".",'p');//创建key
	if(key<0)
	{
		perror("ftok");
	}
	
	int msgid=msgget(key,0664 | IPC_CREAT);//创建消息队列
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}
	
	MSG msg;		//定义消息队列结构体变量
	char buf[64]={0};
	
	while(1)
	{
		memset(&msg,0,sizeof(MSG));	//清空结构体
		msgrcv(msgid,&msg,LEN,typeA,0);//接收数据A
		if(strcmp(msg.mtext,"quit\n")==0)
		{
			printf("progream end\n");
			msg.mtype=typeB;	//定义结构体类型
			strcpy(msg.mtext,"quit\n");//发送quit给对方
			msgsnd(msgid,&msg,LEN,0);//发送数据
			break;
		}
		
		printf("recv:%s",msg.mtext);	//打印
		
		msg.mtype=typeB;	//定义结构体类型
		printf("input:\n");
		fgets(buf,64,stdin);	//获取数据
		strcpy(msg.mtext,buf);	//拷贝数据
		msgsnd(msgid,&msg,LEN,0);//发送数据B		
	}	
	
	int ret=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
	if(ret<0)
	{
		perror("msgctl");
		exit(-1);
	}
    return 0;
} 

write:

/*===============================================
*   文件名称:write_msg.c
*   创 建 者:     
*   创建日期:2022年08月11日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

#define LEN (sizeof(MSG)-sizeof(long))
#define typeA 100
#define typeB 200

typedef struct msgbuf
{
	long mtype;
	char mtext[64];
}MSG;

int main(int argc, char *argv[])
{ 

	key_t key=ftok(".",'p');//创建key
	if(key<0)
	{
		perror("ftok");
	}
	
	int msgid=msgget(key,0664 | IPC_CREAT);//创建消息队列
	if(msgid<0)
	{
		perror("msgget");
		exit(-1);
	}
	
	MSG msg;		//定义消息队列结构体变量
	char buf[64]={0};
	
	
	while(1)
	{	
		
		msg.mtype=typeA;	//定义结构体类型
		printf("input:\n");
		fgets(buf,64,stdin);	//获取数据

		strcpy(msg.mtext,buf);	//拷贝数据
		msgsnd(msgid,&msg,LEN,0);//发送数据A
		
		memset(&msg,0,sizeof(MSG));	//清空结构体
		msgrcv(msgid,&msg,LEN,typeB,0);//接收数据B
		if(strcmp(msg.mtext,"quit\n")==0)//判断是否接收到quit
		{
			printf("progream end\n");
			msg.mtype=typeA;	//定义结构体类型
			strcpy(msg.mtext,"quit\n");//发送quit给对方
			msgsnd(msgid,&msg,LEN,0);//发送数据
			break;
		}
		
		printf("recv:%s",msg.mtext);
	}	
	int ret=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
	if(ret<0)
	{
		perror("msgctl");
		exit(-1);
	}

    return 0;
} 

 


网站公告

今日签到

点亮在社区的每一天
去签到