Linux系统编程之进程间通信(IPC)

师承——陈立臣


进程间通信分类

管道(无名管道、命名管道)消息队列信号量共享内存socket套接字streams


一、管道

1.无名管道

特点:
1.无名管道只适用于亲缘进程(父子进程,兄弟进程);
2.无名管道拥有固定的读端,写端,是半双工的。数据只能单向流动;
3.无名管道是一种特殊的文件,不属于文件系统,只存在于内存中。(建议搜索Linux中的七大文件类型

创建无名管道

父进程读,子进程写:

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

#include<stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


int main()
{
	int ret;
	pid_t pid;
	int pipefd[2];
	char* buf;
	buf=(char*)malloc(sizeof(buf)+8);
	ret=pipe(pipefd);
	if(ret<0){
		printf("create pipe failed!\n");
		return -1;
	}
	pid=fork();
	if(pid>0){
		printf("this is father!\n");
		close(pipefd[1]);
		read(pipefd[0],buf,sizeof(buf)+8);
		printf("i get mes:%s\n",buf);
		wait(NULL);
	}
	else if(pid==0){
		printf("this is child!\n");
		close(pipefd[0]);
		write(pipefd[1],"hello pipe",strlen("hello pipe"));
		exit(0);
	}
	
	
	return 0;
}

2.命名管道(FIFO)

特点:
1.全双工,可以在无关的进程之间交换数据
2.存在于文件系统当中

命名管道编程实战

read.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<stdlib.h>


int main()
{
	int ret;
	int fd;
	char* buf;
	buf=(char*)malloc(sizeof(buf)*10);
	ret=mkfifo("./fifo",0600);//创建命名管道,会在当前文件夹生成相应的文件名
	if(ret<0){
		printf("create fifo failed!\n");
		perror("why");
	}
	fd=open("./fifo",O_RDONLY);//打开命名管道文件
	if(fd<0){
		printf("open failed!\n");
	}
	read(fd,buf,sizeof(buf)*10);//读出命名管道中的数据,若没有则阻塞
	printf("get data from write:%s\n",buf);
	close(fd);
	return 0;
}


write.c

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<string.h>
#include <unistd.h>



int main()
{
	int fd;
	fd=open("./fifo",O_WRONLY);//打开命名管道文件
	if(fd<0){
		printf("open failed!\n");
	}

	write(fd,"this is from write",strlen("this is from write"));//向命名管道文件中写入数据
	close(fd);
	return 0;
}


二、消息队列

消息对列实际上是一个消息链表,存在于内核当中,一个消息队列由一个标识符(队列ID)标识。
特点:
1.消息队列是面向记录的(消息队列是由链表组成,每一个链表节点就是一个结构体),其中的消息有特定的格式以及特定的优先级
2.消息队列由内核掌控,读写进程终止,消息队列中的内容不会删除
3.随机查询,不一定按照先进先出的顺序读写,也可以按照消息类型读写。
在这里插入图片描述

1.创建消息队列

思路:
1.创建消息队列;
2.B进程如何加消息(数据)到队列;
3.A进程如何从队列获取消息(数据);
msgsend.c

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

struct msgbuf {
    long mtype;       /* message type, must be > 0 */
    char mtext[128];    /* message data */
};

int main()
{

	int msgId;
	key_t key;
	struct msgbuf sendbuf={
		.mtype=888,
		.mtext="this is from send"
	};
	struct msgbuf readbuf;
	key=ftok(".",1);//获取键值,也就是id号
        printf("the key is %x\n",key);

	msgId=msgget(key,IPC_CREAT|0777);
	if(msgId<0){
		printf("create msg queue failed1\n");
		perror("failed");
	}
	//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
	msgsnd(msgId,&sendbuf,sizeof(sendbuf.mtext),0);
	printf("send over!\n");
	msgrcv(msgId,&readbuf,sizeof(readbuf.mtext),988,0);
	printf("get msg from 988 queue:%s\n",readbuf.mtext);
	return 0;
}

msgread.c

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

struct msgbuf {
    long mtype;       /* message type, must be > 0 */
    char mtext[128];    /* message data */
};

int main()
{

	int msgId;
	key_t key;
	struct msgbuf readbuf;
	struct msgbuf sendbuf={
		.mtype=988,
		.mtext="read finsh now it's send for read pro"
	};
	key=ftok(".",1);//获取key键值,在消息队列,信号量,共享内存都要使用
	printf("the key is %x\n",key);
	msgId=msgget(key,IPC_CREAT|0777);//创建消息队列返回消息队列的ID号
	if(msgId<0){
		printf("create msg queue failed1\n");
		perror("failed");
	}
	 //ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
	msgrcv(msgId,&readbuf,sizeof(readbuf.mtext),888,0);//从消息队列中读取数据
	printf("get msg from 888 queue:%s\n",readbuf.mtext);
	printf("read over!\n");
	msgsnd(msgId,&sendbuf,sizeof(sendbuf.mtext),0);//向消息队列发送数据
	msgctl(msgId,IPC_RMID,NULL);//从消息队列中移除
	return 0;
}

三、共享内存

特点:
共享内存是IPC方式中最快的用的也是最多的,但是也有一定的局限性:若多个进程在同时进行写操作时,共享内存中的数据会出现问题,经常会和信号量一起配合使用。

1.共享内存的创建

思路:
1.创建共享内存
2.映射到独自的进程空间
3.数据交换
4.释放共享内存
在这里插入图片描述

从共享内存读数据:

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<stdlib.h>
#include<unistd.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
	int shmid;
	key_t key;//获取键值
	char* p;
	key=ftok(".",1);

	shmid=shmget(key,1024*4,IPC_CREAT|0666);//创建共享内存,第二个参数必须是一兆的倍数
	if(shmid<0){
		printf("create mem failed!\n");
		return -1;
	}
	//void *shmat(int shmid, const void *shmaddr, int shmflg);
	p=shmat(shmid,0,0);//将共享内存映射到进程中
	printf("shmat ok!\n");
	sleep(5);//睡五秒等待数据读取
	printf("the data from mem is %s\n",p);
	shmdt(p);//释放共享内存

	return 0;
}

向共享内存写数据:

#include<stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
//int shmget(key_t key, size_t size, int shmflg);
int main()
{
	int shmid;
	key_t key;
	char* p;
	key=ftok(".",1);

	shmid=shmget(key,1024*4,0);
	if(shmid<0){
		printf("create mem failed!\n");
		return -1;
	}
	//void *shmat(int shmid, const void *shmaddr, int shmflg);
	p=shmat(shmid,0,0);
	printf("shmat ok!\n");
	strcpy(p,"you are handsome!");//向共享内存的地址写入数据
	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);//删除共享内存
	return 0;
}

2.查看共享内存

ipcs -m

3.删除共享内存

ipcrm -m 共享内存的ID号

四、信号

可以翻阅我之前的博文:
IPC之信号
信号如何携带消息

五、信号量

可以翻阅我之前的博文
信号量

六、套接字(socket)

用于不同的物理机之间通过网络的多机通信
套接字网络编程我打算单独列出来写,后续也将更新在我的主页,请大家点点关注,多多支持!谢谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值