首页 > 系统相关 >Linux系统编程之进程间通信(IPC)

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

时间:2024-06-01 15:59:09浏览次数:30  
标签:IPC semid int printf 间通信 key Linux include

一.进程间通信概述

进程间通信(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;
}

标签:IPC,semid,int,printf,间通信,key,Linux,include
From: https://blog.csdn.net/2303_77402228/article/details/139349958

相关文章

  • GraalVM - Java8 Linux AMD64
    使用GraalVM在linuxamd64环境下编译Java8程序的步骤主要包括:下载GraalVM下载native-image安装native-image编译程序1.下载GraalVM可以通过Github的release页面直接下载(往回找,找到支持java8的graalvm-ce-java8-linux-amd64-20.3.2.tar.gz)https://github.com/graalvm/gra......
  • Linux文本文件管理003
    ★排序、去重、统计★1)排序sort-n按照数值排序-r降序排列2)去重uniq过滤相邻、重复的行-c对重复行计数3)统计wc统计文件中的字节数、单词数、行数-l显示行数今天通过使用grep、awk、cut指令和上面几个选项提取文本文件的信息方法1:[root@localhostnginx]#ca......
  • Linux进程管理
    在Linux系统中,进程管理是一个重要的任务。以下是一些常用的进程管理指令总结:1.ps:显示当前系统中的进程信息。可以使用psaux来查看所有用户的进程信息,包括详细的状态、CPU使用率等。psaux2.top:实时显示系统中的进程信息,包括进程ID、用户、CPU使用率、内存使用情况等......
  • 【Linux】如何利用linux项目自动化构建工具-make/Makefile以及vim编辑器构建两个小程
    1.倒计时小程序首先我们Linux中创建目录test1,该目录中包含了makefile文件,和main.c文件(该文件是源文件用于编写倒计时程序的代码)再进行依赖方法和依赖关系的确定: 利用vim编辑器编辑makefile文件:注意:在依赖方法前面加@的作用是,执行make指令后,将对应的依赖方法不显示在屏幕......
  • Linux基础 (九):Linux 进程复制与替换
       各位看官,本篇博客干货满满,请耐下心来,慢慢吸收!哈哈哈,内功一定会大增!目录一、printf函数输出问题1.1第1个示例代码1.2第2个示例代码1.3分析与结论二、主函数参数介绍三、复制进程fork3.1进程的基本概念3.2fork()方法3.3fork方法使用示例3.4 面试题fo......
  • 在Linux中,如何进行系统资源的监控?
    在Linux系统中,监控系统资源对于确保系统稳定运行、及时发现并解决问题至关重要。以下是一些常用的命令和工具,用于监控CPU、内存、磁盘I/O以及其他关键系统资源。1.CPU使用情况top:提供了一个实时的视图,展示了当前正在运行的进程及其CPU和内存使用情况。你可以按不同的列排序,如C......
  • 在Linux中,如何进行硬件性能监控?
    在Linux中,硬件性能监控是确保系统高效运行和及时发现硬件问题的重要环节。以下是一些常用的命令和工具,用于监控CPU、内存、磁盘、网络接口以及特定硬件组件(如温度、电压等)的状态。1.CPU监控top和htop:实时显示各进程的CPU使用情况,有助于识别CPU使用率高的进程。mpstat(多处理......
  • 在Linux中,如何进行网络服务的监控?
    在Linux中,网络服务的监控涉及多个方面,包括但不限于网络连接状态、带宽使用情况、网络接口性能、以及服务的可用性和响应时间。以下是一些常用的命令和工具,帮助你进行网络服务的监控:1.网络接口状态与带宽监控ifconfig或ipaddr:查看网络接口的基本信息,如IP地址、子网掩码、MAC......
  • 在Linux中,如何进行容器技术的应用?
    在Linux中应用容器技术主要是通过Docker或类似的容器管理系统来实现的。容器技术允许你将应用程序及其依赖打包在轻量级、可移植的容器中,实现快速部署和隔离运行。以下是使用Docker进行容器技术应用的步骤:1.安装Docker首先,需要在Linux系统上安装Docker。对于基于Debian的系统(如......
  • 在Linux中,如何进行虚拟化技术的应用?
    在Linux中应用虚拟化技术,主要涉及搭建和管理虚拟化环境,以实现资源的高效利用和灵活部署。以下是在Linux上使用KVM(Kernel-basedVirtualMachine)这一常见虚拟化技术的应用步骤:1.检查硬件虚拟化支持确保你的CPU支持硬件虚拟化(如Intel的VT-x或AMD的AMD-V)。使用以下命令检查:egre......