一文看懂linux进程单机通信

本文大致介绍linux几种基本单机通信方式,并附测试实现代码,有问题可随时找我或及时留言

通信概述

linux进程间通信是通过在内核空间定义对象通信 (基于文件IO的思想)
进程存在于用户空间中,两个在用户空间的进程不可直接进行通信,必须通过内核空间,进程A通过系统调用函数在内核空间创建一个对象,来达到与进程B的通信

一般分为单机模式(一个Linux),socket(两个linux内核),本篇博客主要介绍在单机模式下的6种进程间的通信方式
单机模式下进程通信的大致分类:

定义对象方式通信方式
管道通信无名管道
有名管道
信号通信信号的发送、接收、处理
IPC共享内存
消息队列
信号灯

管道通信

无名管道

无名管道在文件系统中不存在文件节点(在内核下)
由单向顺序队列实现

特点

  1. 读完删除
  2. 读阻塞、写阻塞
  3. 无名管道只能实现父子进程

具体实现

int pipe(int pipefd[2])		//函数名称
包含头文件	#include <unistd.h>
参数:		pipefd[0]代表读	pipefd[1]代表写
返回值:		管道创建成功则返回0,出错返回-1

测试代码

int main()		//子写父读
  6 {
  7     int i = 0;
  8     int fd[2] = {0};
  9     int ret;
 10     pid_t pid;
 11     char process_inter[128] = {0};
 12     ret = pipe(fd);
 13     if(ret < 0)
 14     {
 15         printf("creat failure");
 16         exit(1);
 17     }
 18 
 19     pid = fork();
 20     if( pid > 0)        //父进程
 21     {
 22         read(fd[0], &process_inter, sizeof(process_inter)); //if pipe NULL sleep
 23         printf("%s\n", process_inter);
 24         for(i = 0; i < 5; i++)
 25         {
 26             printf("this is father process i = %d\n", i);
 27             usleep(100);
 28         }
 29     }
 30     if(pid == 0)        //子进程
 31     {
 32         for(i = 0; i < 5; i++)
 33         {
 34             printf("this is child process i=%d\n", i);
 35             usleep(100);
 36         }
 37         scanf("%s", process_inter);
 38         sleep(2);
 39         write(fd[1], &process_inter, sizeof(process_inter));
 40     }
 41     close(fd[0]);
 42     close(fd[1]);
 43     return 0;

有名管道

有名管道在文件系统中有文件节点

特点

  1. 读完删除
  2. 读阻塞、写阻塞
  3. 有名管道可实现无血缘关系的进程间通信

具体实现

int mkfifo (const char* filename, mode_t mode)		//函数名称
包含头文件	
			#include <sys/types.h>
       		#include <sys/stat.h>

参数:		const char*filename :	创建的管道文件(p)名称
				mode_t mode				文件权限,与遮罩码umask有关
返回值:		管道创建成功则返回0,出错返回-1

***注意:只有再用open打开管道文件时,才在内核空间生成管道缓存
实现函数

int main ()				//文件1	先运行,创建管道文件且写入
 11 {
 12     int i = 0;
 13     int ret;
 14     int fd;
 15     char buf[128] = {0};
 16     if(mkfifo("./myfifo", 0777) < 0)
 17     {
 18         perror("mkfifo");
 19         exit(1);
 20     }
 21     printf("mkfifo create success!!\n");
 22     fd  = open("./myfifo", O_WRONLY);
 23     if(fd == -1)
 24     {
 25         perror("open");
 26         exit(1);
 27     }
 28 
 29     for (i = 0; i < 5; i++)
 30     {
 31         printf("this is first process i=%d\n", i);
 32     }
 33     printf("请输入:\n");
 34     while(1)
 35     {
 36         scanf("%s",buf);
 37         write(fd, buf, sizeof(buf));
 38         if(strcmp(buf,"bye") == 0)
 39         {
 40             break;
 41         }
 42         memset(buf, 0, sizeof(buf));//清空buf内容
 43     }
 44     close(fd);
 45     unlink("./myfifo");         //删除管道文件
 46     return 0;
 47 }
 11 int main ()		//文件2	读管道文件
 12 {
 13     int i = 0;
 14     int fd = open("./myfifo", O_RDONLY);
 15     char buf[128] = {0};
 16     if(fd == -1)
 17     {
 18         perror("open2");
 19         exit(2);
 20     }
 21     for (i = 0; i < 5; i++)
 22     {
 23         printf("this is second process i=%d\n", i);
 24     }
 25     while(1)
 26     {
 27         sleep(1);
 28         read(fd, buf, sizeof(buf));
 29         if(strcmp(buf,"bye") == 0)
 30         {
 31             break;
 32         }
 33         printf("%s\n",buf);
 34     }
 35     close(fd);
 36     unlink("./myfifo");
 37     return 0;
 38 }

测试结果
在这里插入图片描述

信号通信

进程A在内核空间创建信号对象,通过外部输入或者调用系统函数,发送信号来给另一个不相干的进程B执行相应操作
整个通信过程可分为: 信号的发送、信号的接收、信号的处理

常见的信号一般有64种,可通过kill -l来查找

20 SIGTSTP //ctrl+z 进程切换到后台可通过fg命令来显示后台隐藏程序
2 SIGINT //ctrl+c 关闭进程

信号通信的函数

信号的发送:	int kill(pid_t pid, int sig);		//进程pid号, 具体信号
			int raise(int sig);				//给自己进程发消息
			unsigned int alarm(unsigned int seconds);	//alarm函数在经过seconds秒后給当前进程发送SIGALRM信号(默认终止)
信号的接收:  int pause(void);				//挂起进程,知道当前进程收到信号
			unsigned int sleep(unsigned int seconds);	//休眠seconds秒
			int usleep(useconds_t usec);			//休眠usec微秒
信号的处理:  sighandler_t signal(int signum, sighandler_t handler); //信号,忽略或||处理函数
			exit类似于 信号函数signal(17, ----);

*****signal(14,SIG_IGN); //可忽略输入的14信号

具体实现

void myfun(int signum)
{
    int i;
    i= 0;
    while(i < 5)
    {   
        printf("process signal = %d\n", signum);
        sleep(1);
        i++;
    }   
    //  return 0;
}

int main()
{   
    int i;
    i = 0;
    signal(2,myfun);
    printf("alarm  before\n");
    alarm(9);
    signal(14,SIG_IGN);
    printf("alarm  after\n");
    while(i < 20) 
    {   
        i++;
        printf("process %d\n", i); 
        sleep(1);
    }   
    return 0;
}

在这里插入图片描述

IPC通信

IPC对象:共享内存、消息队列、信号灯

共享内存

创建共享内存、映射、操作、销毁

共享内存的函数


  1 //无血缘关系的A进程共享内存通信	A进程


 12 struct mybuf    //定义缓存内部的结构体
 13 {
 14     int pid;
 15     char buf[124];
 16 };
 17 void myfun(int signum)
 18 {
 19     return;
 20 }
 21 
 22 int main()
 23 {
 24     int shmid;
 25     int key;
 26     pid_t pid;
 27     struct mybuf *p;
 28     key = ftok("./a.c", 'b');
 29     if(key == -1)
 30     {
 31         perror("key");
 32         exit(1);
 33     }
 34     printf("key create success = %x\n", key);
 35     shmid = shmget(key, 128, IPC_CREAT | 0777);
 36     if(shmid == -1)
 37     {
 38         perror("shmid");
 39         exit(1);
 40     }
 41     printf("creative shmid success shmid = %d\n", shmid);
 42 
 43     signal(SIGUSR2, myfun);
 44     //  system("ipcs -m");          //查看ipc对象shmid号
 45     p = (struct mybuf*)shmat (shmid,NULL,0);
 46     if(p == NULL)
 47      {
 48         perror("fathere shmat failure");
 49         exit(1);
 50     }
 51 
 52     //get client pid
 53     p->pid = getpid();  //把服务端的pid写入共享内存
 54     pause();
 55     pid = p->pid;
 56     while(1)
 57     {
 58         //write share menory
 59         printf("A:\n");
 60         fgets(p->buf, 128, stdin);      //键盘输入
 61         //printf("p.buf-----------==%s",p->buf);
 62         //if(strcmp(p->buf, "bye") == 0)
 63         //  break;
 64         kill(pid, SIGUSR1);
 65         pause();    //等待子进程读
 66 
 67     }
 68 
 69     shmdt(p);       //用户空间的映射缓存销毁
 70     shmctl(shmid, IPC_RMID, NULL);  //内核空间的缓存清除
 71 //  system("ipcs -m");
 72 //  system("ipcrm -m shmid");   //删除ipc对象shmid号
 73     return 0;
 74 }
 //无血缘关系的B进程共享内存通信	B进程

 11 struct mybuf
 12 {
 13     int pid;
 14     char buf[124];
 15 };
 16 void myfun(int signum)
 17 {
 18     return;
 19 }
 20 
 21 int main()
 22 {
 23     int shmid;
 24     int key;
 25     struct mybuf *p;
 26     pid_t pid;
 27     key = ftok("./a.c", 'b');
 28     if(key == -1)
 29     {
 30         perror("key");
 31         exit(1);
 32     }
 33     printf("key create success = %x\n", key);
 34     shmid = shmget(key, 128, IPC_CREAT | 0777);
 35     if(shmid == -1)
 36     {
 37         perror("shmid");
 38         exit(1);
 39     }
 40     printf("creative shmid success shmid = %d\n", shmid);
 41 
 42     signal(SIGUSR1, myfun);
 43     //  system("ipcs -m");          //查看ipc对象shmid号
 44     p = (struct mybuf*)shmat (shmid,NULL,0);
 45     if(p == NULL)
 46     {
 47         perror("fathere shmat failure");
 48         exit(1);
 49     }
 50     pid = p->pid;   //read  Apid
 51     p->pid = getpid();  //write Bpid
 52     kill(pid, SIGUSR2);
 53 
 54     while(1)
 55     {
 56         pause();    //等待Awrite
 57         printf("B:%s", p->buf);
 58     //  if(strcmp(p->buf, "bye") == 0)
 59     //  {
 60     //      printf("-------------");
 61     //      break;
 62     //  }
 63         kill(pid,SIGUSR2);      //读完发信号给A可以开始写
 64     }
 65 
 66     shmdt(p);       //用户空间的映射缓存销毁
 67     shmctl(shmid, IPC_RMID, NULL);  //内核空间的缓存清除
 68 //  system("ipcs -m");
 69 //  system("ipcrm -m shmid");   //删除ipc对象shmid号
 70     return 0;
 71 }

运行结果
在这里插入图片描述

消息队列

相当于链式队列

测试代码 可实现双向传输

 //A进程,创建消息队列,write 100 read 200
 struct msgbuf
 10 {
 11     long type;
 12     char voltage[124];
 13     char ID[4];
 14 };
 15 
 16 int main ()
 17 {
 18     struct msgbuf sendbuf, recvbuf;
 19     int readret;
 20     int msgpid;
 21     int key;
 22     pid_t pid;
 23     key = ftok("./a.c",'a');
 24     if(key == -1)
 25     {
 26         perror("key");
 27         exit(1);
 28     }
 29     msgpid = msgget(key, IPC_CREAT | 0777);
 30     if(msgpid == -1)
 31     {
 32         perror("msgget:");
 33         exit(1);
 34     }
 35     printf("msgpid=%d\n",msgpid);
 36     pid = fork();
 37     if(pid > 0)     //父进程    write 100
 38     {
 39         sendbuf.type = 100;
 40         //write
 41         while(1)
 42         {
 43             memset(sendbuf.voltage, 0, 124);
 44             printf("write:");
 45             fgets(sendbuf.voltage,124,stdin);
 46             msgsnd(msgpid,(void *)&sendbuf, strlen(sendbuf.voltage), 0);
 47 //      if(strcmp(sendbuf.voltage, "bye") == 0)
 48 //      {
 49 //          break;
 50 //      }
 51         }
 52 
 53     }
 54     if (pid == 0)   //read 200
 55     {
 56         while(1)
 57         {
 58             memset(recvbuf.voltage, 0, 124);
 59             msgrcv(msgpid,(void *)&recvbuf, 124, 200, 0);
 60             printf("read:%s", recvbuf.voltage);
 61         }
 62 
 63     }
 64     msgctl(msgpid, IPC_RMID, NULL);
 65     system("ipcs -q");
 66     return 0;
 67 }
//B进程,创建消息队列,write 200 read 100
  9 struct msgbuf
 10 {
 11     long type;
 12     char voltage[124];
 13     char ID[4];
 14 };
 15 
 16 int main ()
 17 {
 18     struct msgbuf  recvbuf, sendbuf;
 19     int readret;
 20     int msgpid;
 21     int key;
 22     pid_t pid;
 23     key = ftok("./a.c",'a');
 24     if(key == -1)
 25     {
 26         perror("key");
 27         exit(1);
 28     }
 29     msgpid = msgget(key, IPC_CREAT | 0777);
 30     if(msgpid == -1)
 31     {
 32         perror("msgget:");
 33         exit(1);
 34     }
 35     printf("msgpid=%d\n",msgpid);
 36     pid = fork();
 37     if(pid > 0)     //父进程    read 100
 38     {
 39         //read  100
 40         while(1)
 41         {
 42             memset(recvbuf.voltage, 0, 124);
 43             msgrcv(msgpid,(void *)&recvbuf, 124, 100, 0);
 44             printf("read:%s", recvbuf.voltage);
 45         //  if(recvbuf.voltage == "bye")
 46         //  {
 47         //      break;
 48         //  }
 49         }
 50     }
 51     else if(pid == 0)   //子进程  write 200
 52     {
 53         sendbuf.type = 200;
 54         //write
 55         while(1)
 56         {
 57             memset(sendbuf.voltage, 0, 124);
 58             printf("write:\n");
 59             fgets(sendbuf.voltage,124,stdin);
 60             msgsnd(msgpid,(void *)&sendbuf, strlen(sendbuf.voltage), 0);
 61     //     if(strcmp(sendbuf.voltage, "bye") == 0)
 62     //     {
 63     //          break;
 64     //      }
 65     }
 66 
 67         recvbuf.type = 100;
 68     }
 69     msgctl(msgpid, IPC_RMID, NULL);
 70     system("ipcs -q");
 71     return 0;
 72 }                                        

运行结果
在这里插入图片描述

信号灯

测试代码 信号量的集合(a进程创建对象,b先运行)

//	创建信号灯对象,等B进程先执行
	#include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>
  4 #include <sys/ipc.h>
  5 #include <sys/sem.h>
  6 
  7 union semun
  8 {
  9     int val;
 10     struct semid_ds *buf;
 11     unsigned short *array;
 12     struct seminfo *_buf;
 13 };
 14 
 15 int semid;
 16 union semun mysemun;
 17 struct sembuf mysembuf;
 18 int main()
 19 {
 20     int i;
 21     int key;
 22     key = ftok("./1.c", 'a');
 23     if(key == -1)
 24     {
 25         perror("create key failure\n");
 26         exit(1);
 27     }
 28     semid = semget(key, 3, 0777 | IPC_CREAT);
 29     if(semid == -1)
 30     {
 31         perror("semid");
 32         exit(1);
 33     }
 34 
 35     system("ipcs -s");
 36     mysemun.val = 0;
 37     semctl(semid, 0, SETVAL, mysemun);
 38 
 39     mysembuf.sem_num = 0;
 40     mysembuf.sem_flg = 0;
 41     //p
 42     mysembuf.sem_op = -1;
 43     semop(semid, &mysembuf, 1);
 44 
 45     for(i = 0; i < 9; i++)
 46     {
 47         usleep(100);
 48         printf("this is a fun i = %d\n", i);
 49     }
 50     while(1);
 51     return 0;
 52 }

  1 //a初始化,先运行,运行
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <sys/types.h>
  5 #include <sys/ipc.h>
  6 #include <sys/sem.h>
  7 
  8 union semun
  9 {
 10     int val;
 11     struct semid_ds *buf;
 12     unsigned short *array;
 13     struct seminfo *_buf;
 14 };
 15 
 16 int semid;
 17 union semun mysemun;
 18 struct sembuf mysembuf;
 19 int main()
 20 {
 21     int i;
 22     int key;
 23     key = ftok("./1.c", 'a');
 24     if(key == -1)
 25     {
 26         perror("create key failure\n");
 27         exit(1);
 28     }
 29     semid = semget(key, 3, 0777 | IPC_CREAT);
 30     if(semid == -1)
 31     {
 32         perror("semid");
 33         exit(1);
 34     }
 35 
 36     system("ipcs -s");
 37 //  mysemun.val = 0;
 38 //  semctl(semid, 0, SETVAL, mysemun);
 39 
 40     mysembuf.sem_num = 0;
 41     mysembuf.sem_flg = 0;
 42     for(i = 0; i < 9; i++)
 43     {
 44         usleep(100);
 45         printf("this is b fun i = %d\n", i);
 46     }
 47     //V
 48     mysembuf.sem_op = 1;
 49     semop(semid, &mysembuf, 1);
 50     while(1);
 51     return 0;
 52 }

运行结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值