IPC (管道、FIFO、消息队列、共享内存、信号、信号量)demo

进程间通信(IPC,InterProcess Communication)的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。

一、管道

管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,而fd[1]固定用于写管道。
①半双工通信模式。
②只用于具有亲缘关系的进程之间的通信。
③可看成是一种特殊的文件。

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

//int pipe(int fd[2]);

int main()
{
	int fd[2];
	int ret;
	char buf[128];
	ret = pipe(fd);
	if(ret == -1){
		perror("pipe:");
		exit(-1);
	}

	pid_t pid = fork();

	if(pid < 0){
		perror("create child failed\n");
		exit(-1);
	}else if(pid > 0){
		printf("Please input content:\n");
		fgets(buf,128,stdin);
		close(fd[0]);
		write(fd[1],buf,strlen(buf));
		wait();
	}else{
		memset(buf,0,sizeof(buf));
		close(fd[1]);
		read(fd[0],buf,128);
		printf("read from parent:%s\n",buf);
		exit(0);
	}
	return 0;
}

二、FIFO

命名管道,又称为有名管道,它可以使不相关的进程实现彼此通信。
①命名管道(FIFO)是在文件系统中作为一个特殊的设备文件而存在的。
②不同祖先的进程之间可以通过管道共享数据。
③当共享管道的进程执行完所有的I/O操作以后,命名管道将继续保存在文件系统中以便以后使用。

读端

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

// int mkfifo(const char *pathname,mode_t mode);

int main()
{	
	char buf[128];

	if(mkfifo("./file",0600) == -1 && errno != EEXIST){
            perror("error\n");
        	exit(-1);
	}
      
	int fd = open("./fifofile",O_RDONLY);
	if(fd < 0){
		perror("open fifo:");
		exit(-1);
	}
	while(1){
		memset(buf,0,sizeof(buf));
	    read(fd,buf,128);
		printf("read from write.c: %s",buf);
		if(strstr(buf,"quit") != NULL)
                	break;
	}
	close(fd);
	return 0;
}

写端

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main()
{	
	char buf[128];
	int fd = open("./fifofile",O_WRONLY);
	if(fd == -1){
		perror("fifo:");
		exit(-1);
	}
	while(1){
		memset(buf,0,sizeof(buf));
		printf("Please input content:\n");
		fgets(buf,128,stdin);//从键盘获取内容
		write(fd,buf,strlen(buf));
		if(strstr(buf,"quit") != NULL)
			break;
	}
	close(fd);
	return 0;
}

三、消息队列

消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。
消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。
可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。

msgsend.c

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

/*	创建或打开消息队列:int msgget(key_t key, int flag);
	添加消息:int msgsnd(int msqid, const void *ptr, size_t size, int flag);
	读取消息:int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
	控制消息队列:int msgctl(int msqid, int cmd, struct msqid_ds *buf);
*/
struct msgbuf {
	long mtype;       /* message type, must be > 0 */
    char mtext[128];    /* message data */
};

int main()
{
	key_t key;
    key = ftok(".",1);
    int msgid = msgget(key,IPC_CREAT|0777);
	if(msgid == -1){
		perror("error");
	}
	struct msgbuf sendbuf ={666,"this is send massage"};
	msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

msgrcv.c

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

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

int main()
{
	key_t key;
	key = ftok(".",1);
	int msgid = msgget(key,IPC_CREAT|0777);
	if(msgid == -1){
		perror("error");
	}
	struct msgbuf rcvbuf;
	msgrcv(msgid,&rcvbuf,sizeof(rcvbuf.mtext),666,0);
	printf("read from quen:%s\n",rcvbuf.mtext);
	msgctl(msgid,IPC_RMID,NULL);
	return 0;
}

四、共享内存

共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。

shmw.c

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

/*	创建或获取一个共享内存:int shmget(key_t key, size_t size, int flag);
	连接共享内存到当前进程的地址空间:void *shmat(int shm_id, const void *addr, int flag);
	断开与共享内存的连接:int shmdt(void *addr); 
	控制共享内存的相关信息:int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
*/
int main()
{
	int shmid;
	char *shmaddr;
	key_t key;
	key = ftok(".",2);
	shmid = shmget(key,1024*4,IPC_CREAT|0666);
	if(shmid == -1){
		printf("create failed\n");
		exit(-1);
	}
	
	shmaddr = shmat(shmid,0,0);
	strcpy(shmaddr,"helloha");
	sleep(5);
	shmdt(shmaddr);
	shmctl(shmid,IPC_RMID,NULL);
	return 0;
}

shmr.c

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

int main()
{
	int shmid;
	char *shmaddr;
	key_t key;
	key = ftok(".",2);
	shmid = shmget(key,1024*4,0);
	shmaddr = shmat(shmid,0,0);
	printf("context: %s\n",shmaddr);
	shmdt(shmaddr);
	return 0;
}

五、信号

信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

入门
signal

#include <signal.h>
#include <stdio.h>

void handler(int signum)
{
	printf("get signum %d\n",signum);
	switch(signum){
		case 2:
			printf("SIGINT\n");
			break;
		case 9:
			printf("SIGKILL\n");
	}
	printf("never quit\n");
}

int main()
{
	printf("pid = %d\n",getpid());
	signal(SIGKILL,handler);
	signal(SIGINT,handler);
	while(1);
	return 0;
}

高级
sigaction

#include <signal.h>
#include <stdio.h>

void handler(int signum,siginfo_t *info, void *context)
{
	printf("get signum %d\n",signum);
	
	if(context != NULL){
		printf("get data: %d\n",info->si_int);
		printf("get data: %d\n",info->si_value.sival_int);
		printf("from  %d\n",info->si_pid);
	}
}

int main()
{
	struct sigaction act;
	printf("pid = %d\n",getpid());
	act.sa_sigaction = handler;
	act.sa_flags =  SA_SIGINFO;

	sigaction(SIGUSR1,&act,NULL);

	while(1);
	return 0;
}

sendsigaction

#include <signal.h>
#include <stdio.h>

int main(int argc, char **argv)
{
	int signum = atoi(argv[1]);
	int pid = atoi(argv[2]);
	
	union sigval value;
	value.sival_int = 100;
	sigqueue(pid,signum,value);
	printf("pid = %d done\n",getpid());
	return 0;
}

六、信号量

信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
支持信号量组。

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

/*	创建或获取一个信号量组:int semget(key_t key, int num_sems, int sem_flags);
	对信号量组进行操作,改变信号量的值:int semop(int semid, struct sembuf semoparray[], size_t numops);  
	控制信号量的相关信息:int semctl(int semid, int sem_num, int cmd, ...);
*/

union semun {
		int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};

void pgetkey(int id)
{
	struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = -1;
    sops.sem_flg = SEM_UNDO;
    semop(id, &sops, 1);
	printf("get key\n");
}

void vputkey(int id)
{
	struct sembuf sopss;
    sopss.sem_num = 0;
    sopss.sem_op = 1;
    sopss.sem_flg = SEM_UNDO;
    semop(id, &sopss, 1);
//	printf("put key\n");
}

int main(int argc,char **argv)
{
	int semid;
	key_t key;
	key = ftok(".",6);
	semid = semget(key, 1, IPC_CREAT|0666);
	
	union semun initsem;
	initsem.val = 0;
	semctl(semid,0,SETVAL,initsem);
	
	int pid = fork();
	
	if(pid > 0){
			
		pgetkey(semid);
		printf("this is father\n");
		vputkey(semid);
		semctl(semid,0,IPC_RMID);
	}

	else if(pid == 0){
		printf("this is child\n");
		vputkey(semid);
	}else{
		printf("fork error\n");
	} 
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
消息队列共享内存都是进程间进行数据通信的方法,但它们具有不同的特点。 消息队列的特点包括: 1. 消息队列是一种异步通信方式,发送者将消息放入队列后即可继续进行其他操作,而不需要等待接收者处理。 2. 消息队列具有较高的可靠性,即使接收者暂时不可用,消息也会被保存在队列中,直到接收者准备好接收。 3. 消息队列可以实现多对多的通信,即多个发送者可以发送消息给多个接收者。 4. 消息队列通常使用先进先出(FIFO)的方式进行消息传递。 共享内存的特点包括: 1. 共享内存是一种最快的进程间通信方式,进程可以直接读写共享内存中的数据,不需要进行数据的拷贝。 2. 共享内存适用于大量数据的共享和频繁的读写操作,因为共享内存的访问速度很快。 3. 共享内存可以实现多对多的通信,多个进程可以同时访问同一块共享内存。 4. 使用共享内存需要进行互斥处理,以确保多个进程对共享内存的访问不会造成冲突。 综上所述,消息队列适用于异步通信和可靠性要求较高的场景,而共享内存适用于需要快速读写大量数据的场景,并且需要进行互斥处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [linux网络编程](https://download.csdn.net/download/zhushouxuan8369/11323400)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Linux中的消息队列共享内存,你确定都掌握了吗?](https://blog.csdn.net/2004v2004/article/details/127222470)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [linux 管道消息队列共享内存的对比](https://blog.csdn.net/weixin_42512356/article/details/116666081)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值