天天看点

Linux下C编程:进程间通信(IPC)总结

(1)Linux信号:

某种信号相当于某种事件,一般用于内核告诉进程某种事件发生了,进程通过signal函数注册信号的处理函数。我个人体会在用户态中两个进程之间用信号进行进程间通信应该不是一个特别好的方法,限制比较多。

(2)匿名管道:

int pipe(int fdes[2]);//创建匿名管道

管道的都写方法和文件文件读写方法相同

匿名管道一般用在父进程和子进程之间的数据通信,而且匿名管道是在内核中临时存储的,程序运行结束后,就不存在了。

(3)命名管道:任何两个进程之间都可以通过命名管道去通信,命名管道是作为特殊设备文件存储在文件系统中的,当程序运行结束后,它继续存在于文件系统中,除非删除该文件。Linix Shell中可以看到命名管道文件名后面紧跟一个|,可以通过S_ISFIFO宏来检测一个文件是否是命名管道。

下面给出一个通过命名管道通信的一个客户端-服务端程序,实现的功能是客户端在终端输入字符串,写入管道,服务器端从管道读出字符串,并显示在终端上。具体的可以参加《精通Linux C编程一书》

服务器端程序:

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

#define FIFO_FILE "MYFIFO"

int main()
{
	FILE *fp;
	char readbuf[80];
	if((fp=fopen(FIFO_FILE,"r"))==NULL)
	{
		umask(0);
		mknod(FIFO_FILE,S_IFIFO|0666,0);
	}
	else 
		fclose(fp);
	while(1)
	{
		if((fp=fopen(FIFO_FILE,"r"))==NULL)
		{
			printf("open fifo failed. \n");
			exit(1);
		}
		if(fgets(readbuf,80,fp)!=NULL)
		{
			printf("Received string :%s \n", readbuf);
			fclose(fp);
		}
		else
		{
			if(ferror(fp))
			{
				printf("read fifo failed.\n");
				exit(1);
			}
		}
	}
	return 0;
}           

客户端程序:

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

#define FIFO_FILE "MYFIFO"

int main(int argc, char *argv[])
{
	FILE *fp;
	int i;
	if(argc<=1)
	{
		printf("usage: %s <pathname>\n",argv[0]);
		exit(1);
	}
	if((fp=fopen(FIFO_FILE,"w"))==NULL)
	{
		printf("open fifo failed. \n");
		exit(1);
	}
	for(i=1;i<argc;i++)
	{
		if(fputs(argv[i],fp)==EOF)
		{
			printf("write fifo error. \n");
			exit(1);
		}
		if(fputs(" ",fp)==EOF)
		{
			printf("write fifo error. \n");
			exit(1);
		}
	}
	fclose(fp);
	return 0;
}           

除了上面三种方法,Linux还支持Unix System V的IPC机制,消息队列、信号量及共享内存,这几种方法在编程接口和内部实现上都非常像。

(4)消息队列:

int msgget(key_t key, int flag); //创建或打开消息队列

int msgsnd(int msqid, const void* ptr, size_t nbyte, in flag); //向消息队列发送消息

int msgrcv(int msqid, const void* ptr, size_t nbyte, long type in flag); //从消息队列中取出消息

个人感觉消息队列用于进程间的通信是非常灵活和方便的。

(5)信号量:

信号量实际是一个整型计数器,主要用来控制多个进程对共享资源的访问,比如实现关键区。

(6)共享内存:

和Windows中的内存映射文件类似,用共享内存文件进行进程间数据交换的最大好处我认为就是简单,每个进程访问共享内存的时候和访问其他内存没什么区别。不过共享内存有一个问题是,如果多个进程同时对共享内存进行修改,则需要通过信号量等机制进行同步控制。

int shmget(key_t key, int size, int flag); //创建或打开共享内存

void * shmat(int shmid, void *addr, int flag); //将共享内存附加到进程的地址空间中

int shmdt(void *addr); //取消共享内存和进程的地址空间的关系

继续阅读