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

一.进程间通信概述

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC

二.管道

1.匿名管道

(1)特点

1.半双工,具有固定的写端和读端

2.只能用与具有亲缘关系的进程之间的通信(父子进程和兄弟进程之间)

3.可以看成一种特殊的文件,不属于其他任何文件系统,只存在于内存中

4.管道中的数据读走就没了

(2)API

int pipe(int pipefd[2])

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

fd[0]:读端,为读而打开 

fd[1]:写端,为写而打开

关闭管道:关闭读端和写端      

使用write函数进行写入,使用read函数进行读出,使用close函数关闭

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
	int fd[2];

	int pid;

	char buf[128];

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

	if(pipe(fd) == -1){
		printf("creat pipe failed\n");
	}
	pid = fork();
	
	if(pid<0){
		printf("creat child failed\n");
	}
	else if(pid > 0){
		sleep(3);
		printf("this is father\n");

		close(fd[0]);
		write(fd[1],"hello from father",strlen("hello form father"));
		wait();
	}else{
		printf("this is child\n");
		close(fd[1]);
		read(fd[0],buf,128);
		printf("read from father: %s\n",buf);
		exit(0);
	}
	

	return 0;
}

 2.有名管道

(1)特点

1.可以在无关的进程之间交换数据

2.有路径名,以一种特别设备文件形式存在于文件系统中,可以用一般的文件I/O函数操作

(2)API

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

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

write.c

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

//       int mkfifo(const char *pathname, mode_t mode);
int main()
{
	int cnt = 0;
	char *str = "message from fifo";

    if( (mkfifo("./file",IPC_CREAT|0600) == -1) && errno!=EEXIST){
		printf("mkfifo failuer\n");
		perror("why");
	}

	int fd = open("./file",O_WRONLY);
	printf("write open success\n");
	
	while(1){
		
		write(fd, str, strlen(str));
		sleep(1);
		if(cnt == 5){
			break;	
		}
	}
	close(fd);
	return 0;
}


read.c

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

//       int mkfifo(const char *pathname, mode_t mode);
int main()
{
	char buf[30] = {0};
	int nread = 0;


	if( (mkfifo("./file",0600) == -1) && errno!=EEXIST){
		printf("mkfifo failuer\n");
		perror("why");
	}

	int fd = open("./file",O_RDONLY);
	printf("open success\n");
	
	while(1){
		nread = read(fd,buf,30);
	
		printf("read %d byte from fifo,context:%s\n",nread,buf);
	}
	close(fd);
	return 0;
}


三.消息队列

1.特点

1.消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先权

2.消息队列对立与发送与接收进程,进程终止时,消息队列及其内容并不会被删除

3.消息队列可以实现消息的随即查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取

2.API

1.创建或打开消息队列

int msgget(key_t key, int msgflg);
返回值:成功返回队列ID,失败返回-1

2.添加消息

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

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

3.读取消息

 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
返回值:成功返回消息数据的长度,失败返回-1

4.控制消息队列

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

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

msgget创建一个新队列:

1.如果没有与键值key对应的消息队列,并且flag中包含了IPC_CREAT标志位

2.key参数为IPC_PRIVATE,创建一个私有消息队列

msgrcv在读取时的type参数

type 含义
==0 返回消息队列中的第一个消息
>0 返回队列中消息类型为type的第一个消息
<0 返回队列中消息类型值小于或等于type绝对值的消息,如果有多个,则取类型值最小的消息

msgSend.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//       int msgget(key_t key, int msgflg);
//        int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

//       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
//                      int msgflg);
struct msgbuf {
               
	long mtype;       /* message type, must be > 0 */
        char mtext[256];    /* message data */
};


int main()
{
	//1.huoqu
	struct msgbuf sendBuf = {888,"this is message from quen"};	
	struct msgbuf readBuf;

	memset(&readBuf,0,sizeof(struct msgbuf));
	key_t key;
        key = ftok(".",'m');
        printf("key=%x\n",key);

        int msgId = msgget(key, IPC_CREAT|0777);

	if(msgId == -1 ){
		printf("get que failuer\n");
	}
	
	msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
	printf("send over\n");

        msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),988,0);
	printf("reaturn from get:%s\n",readBuf.mtext);
	
	msgctl(msgId,IPC_RMID,NULL);
	
	return 0;
}

msgGet.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//       int msgget(key_t key, int msgflg);
//        int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

//       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
//                      int msgflg);
struct msgbuf {
               
	long mtype;       /* message type, must be > 0 */
        char mtext[256];    /* message data */
};


int main()
{
	//1.huoqu
	struct msgbuf readBuf;	


	key_t key;
	key = ftok(".",'m');
	printf("key=%x\n",key);

	int msgId = msgget(key, IPC_CREAT|0777);
	if(msgId == -1 ){
		printf("get que failuer\n");
	}
	memset(&readBuf,0,sizeof(struct msgbuf));

	msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),888,0);	
	printf("read from que:%s\n",readBuf.mtext);

        struct msgbuf sendBuf = {988,"thank you for reach"};
        msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);

	msgctl(msgId,IPC_RMID,NULL);

	return 0;
}

四.共享内存

1.注意事项

共享内存大小以M对齐

2.API

1.创建或获取一个共享内存

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

返回值:成功返回共享内存ID,失败返回-1

2.连接共享内存到当前进程的地址空间

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

返回值:成功返回指向共享内存的指针,失败返回-1

shmflg = 0即为可读可写

shmaddr = 0即让内存分配共享空间

3.断开与共享内存的连接

int shmdt(const void *shmaddr);

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

4.控制共享内存的相关信息

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

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

ipcs -m:查看系统中有哪些共享内存

ipcrm -m 共享内存ID :删除共享内存

shmw.c

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

//int shmget(key_t key, size_t size, int shmflg);
int main()
{
	
	int shmid;
	char *shmaddr;

	
	key_t key;
	key = ftok(".",1);
	
	shmid = shmget(key,1024*4,IPC_CREAT|0666);
	if(shmid == -1){
		printf("shmget noOk\n");
		exit(-1);
	}
	shmaddr = shmat(shmid,0,0);

	printf("shmat ok\n");
	strcpy(shmaddr,"chenlichen");

	sleep(5);
	shmdt(shmaddr);
	shmctl(shmid, IPC_RMID, 0);

	printf("quit\n");
	
	return 0;
}

shmr.c

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

//int shmget(key_t key, size_t size, int shmflg);
int main()
{
	
	int shmid;
	char *shmaddr;

	
	key_t key;
	key = ftok(".",1);
	
	shmid = shmget(key,1024*4,0);
	if(shmid == -1){
		printf("shmget noOk\n");
		exit(-1);
	}
	shmaddr = shmat(shmid,0,0);

	printf("shmat ok\n");
	printf("data: %s\n:",shmaddr);

	shmdt(shmaddr);

	printf("quit\n");
	
	return 0;
}

五.信号

1.概述

kill -l:查看系统中所有信号

信号处理:忽略、捕捉或默认动作

SIGKILL、SIGSTOP不可忽略

2.API

1.信号处理函数的注册

sighandler_t signal(int signum, sighandler_t handler);

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

忽略信号:SIG_IGN

kill -信号id 进程号:给指定进程发送指定信号

 struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);        //最后一个参数非空为有数据,为空就是没数据
               sigset_t   sa_mask;        //默认阻塞,处理一个信号
时不处理其他信号               

                int        sa_flags;        //SA_SIGINFO:收数据
           };

2.信号发送函数

int kill(pid_t pid, int sig);

 int sigqueue(pid_t pid, int sig, const union sigval value);

union sigval {
               int   sival_int;
               void *sival_ptr;
           };
signalDemo1.c

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

//       typedef void (*sighandler_t)(int);

//       sighandler_t signal(int signum, sighandler_t handler);

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

	}




	printf("never quit\n");
}

int main()
{
	signal(SIGINT,SIG_IGN);
	signal(SIGKILL,SIG_IGN);
	signal(SIGUSR1,handler);
	while(1);
	return 0;
}


signalDemo1CON.c

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>


int main(int argc ,char **argv)
{
	int signum;
	int pid;

	char cmd[128]={0};

	signum = atoi(argv[1]);
	pid = atoi(argv[2]);

	printf("num=%d,pid=%d\n",signum,pid);	

//	kill(pid, signum);
	sprintf(cmd,"kill -%d %d",signum,pid);

	
	system(cmd);

	printf("send signal ok");	
	return 0;
}


NiceSignal.c

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

//       int sigaction(int signum, const struct sigaction *act,
//                     struct sigaction *oldact);

void   handler(int signum , siginfo_t *info, void *context)
{
	printf("get signum %d\n",signum);
	
	if(context != NULL){

		printf("from:%d\n",info->si_pid);
//		printf("get data=%d\n",info->si_int);
//		printf("get data=%d\n",info->si_value.sival_int);
//		printf("get data=%s\n",context);
		printf("get data=%d\n",*(int *)(info->si_value.sival_ptr));
	}
}

int main()
{
	struct sigaction act;
	printf("pid = %d\n",getpid());

	act.sa_sigaction = handler;
	act.sa_flags = SA_SIGINFO; //be able to get message


	sigaction(SIGUSR1,&act,NULL);
	while(1);
	return 0;

}

sendSignal.c

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

//      int sigqueue(pid_t pid, int sig, const union sigval value)

int main(int argc, char **argv)
{
        int signum;
        int pid;
        union sigval value;

        signum = atoi(argv[1]);
        pid = atoi(argv[2]);
        value.sival_int = 100;

        sigqueue(pid,signum,value);

        printf("%d,done\n",getpid());

        return 0;
}

六.信号量

信号量是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据

1.特点

1.信号量用于进程间同步,若要在进程间传递数据需结合共享内存

2.信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作

3.每次对信号量的PV操作不仅限于对信号量值加1或减1,而且可以加减任意正整数

4.支持信号量组

2.API

1.创建或获取一个信号量组

int semget(key_t key, int nsems, int semflg);

返回值:返回成功返回信号量集ID,失败返回-1

2.对信号量组进行操作

int semop(int semid, struct sembuf *sops, size_t nsops);

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

3.控制信号量的相关信息

int semctl(int semid, int semnum, int cmd, ...);

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

P操作:取信号量

V操作:存信号量

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

//      int semget(key_t key, int nsems, int semflg);
//      int semctl(int semid, int semnum, int cmd, ...);
//      int semop(int semid, struct sembuf *sops, size_t nsops);

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 pHandler(int semid)
{
        struct sembuf sop;

        sop.sem_num = 0;
        sop.sem_op = -1;
        sop.sem_flg = SEM_UNDO;

        semop(semid,&sop,1);
        printf("get key\n");
}

void vHandler(int semid)
{
        struct sembuf sop;

        sop.sem_num = 0;
        sop.sem_op = 1;
        sop.sem_flg = SEM_UNDO;

        semop(semid,&sop,1);
        printf("put back key\n");
}

int main()
{
        key_t key;
        int semid;
        union semun initsem;
        int pid;

        key = ftok(".",2);
        semid = semget(key,1,IPC_CREAT|0666);

        initsem.val = 0;

        semctl(semid,0,SETVAL,initsem);

        pid = fork();
        if(pid > 0){
                pHandler(semid);
                printf("this is father\n");
                vHandler(semid);
                semctl(semid,0,IPC_RMID);
        }else if(pid == 0){
                printf("this is child\n");
                vHandler(semid);
        }else{
                printf("fork falied\n");
        }

        return 0;
}

3.信号量与共享内存结合

send.c

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

//       int semget(key_t key, int nsems, int semflg);
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 pHandler(int semid)
{
        struct sembuf sop;

        sop.sem_num = 0;
        sop.sem_op = -1;
        sop.sem_flg = SEM_UNDO;

        semop(semid,&sop,1);
        printf("get key\n");
}

void vHandler(int semid)
{
        struct sembuf sop;

        sop.sem_num = 0;
        sop.sem_op = 1;
        sop.sem_flg = SEM_UNDO;

        semop(semid,&sop,1);
        printf("put back key\n");
}

int main()
{
        key_t key;
        int semid;
        union semun initsem;
        int shmid;
        char *shm;

        key = ftok(".",3);
        semid = semget(key,1,IPC_CREAT|0666);
        printf("semid = %d\n",semid);
        initsem.val = 0;
        semctl(semid,0,SETVAL,initsem);

        shmid = shmget(key,1024*4,IPC_CREAT|0666);
        shm = shmat(shmid,0,0);

        sprintf(shm,"ccy handsome");
        vHandler(semid);

        sleep(5);

        pHandler(semid);
        printf("context:%s\n",shm);
        vHandler(semid);

        shmdt(shm);
        shmctl(shmid,IPC_RMID,NULL);

        return 0;
}

read.c

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

//       int semget(key_t key, int nsems, int semflg);
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 pHandler(int semid)
{
        struct sembuf sop;

        sop.sem_num = 0;
        sop.sem_op = -1;
        sop.sem_flg = SEM_UNDO;

        semop(semid,&sop,1);
        printf("get key\n");
}

void vHandler(int semid)
{
        struct sembuf sop;

        sop.sem_num = 0;
        sop.sem_op = 1;
        sop.sem_flg = SEM_UNDO;

        semop(semid,&sop,1);
        printf("put back key\n");
}

int main()
{
        key_t key;
        int semid;
        union semun initsem;
        int shmid;
        char *shm;

        key = ftok(".",3);
        semid = semget(key,1,IPC_CREAT|0666);
        printf("semid = %d\n",semid);
        initsem.val = 0;
        semctl(semid,0,SETVAL,initsem);

        shmid = shmget(key,1024*4,IPC_CREAT|0666);
        shm = shmat(shmid,0,0);
        pHandler(semid);
        printf("context:%s\n",shm);
        vHandler(semid);

        pHandler(semid);
        sprintf(shm,"thank you for using");
        vHandler(semid);

        shmdt(shm);
        shmctl(shmid,IPC_RMID,NULL);

        return 0;
}

相关推荐

  1. Linux系统编程进程通信(IPC)

    2024-06-06 14:52:06       29 阅读
  2. Linux进程通信IPC机制

    2024-06-06 14:52:06       28 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-06 14:52:06       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-06 14:52:06       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-06 14:52:06       82 阅读
  4. Python语言-面向对象

    2024-06-06 14:52:06       91 阅读

热门阅读

  1. websocket链接携带参数

    2024-06-06 14:52:06       31 阅读
  2. EVO轨迹评估工具基本使用教程(学习记录)

    2024-06-06 14:52:06       29 阅读
  3. Selenium自动化测试入门:cookie 处理

    2024-06-06 14:52:06       32 阅读
  4. Python库之pandas的高级用法深度解析

    2024-06-06 14:52:06       31 阅读
  5. ubuntu上zsh与bash切换

    2024-06-06 14:52:06       29 阅读
  6. Mac上搭建Python环境:深入探索与高效实践

    2024-06-06 14:52:06       29 阅读
  7. C++函数模版和C#的泛型函数的区别

    2024-06-06 14:52:06       28 阅读
  8. vue 权限分组

    2024-06-06 14:52:06       23 阅读
  9. gin-vue-admin整合 ElasticSearch

    2024-06-06 14:52:06       29 阅读
  10. 如何评价GPT-4o?

    2024-06-06 14:52:06       30 阅读