IPC的方式通常有管道(无名管道,和命名管道),消息队列,信号量,共享内存,socket,streams,

其中socket 和 streams 支持不同主机之间的通信

一.管道

  1. 是半双工的,

  1. 只能亲缘关系的进程之间通信

  1. 读写可以使用read,write等函数

#include<unistd.h>
int pipe(int fd[2]);//成功返回0.失败返回-1

管道建立时,他会创建两个文件描述符

fd[0],为读打开,

fd[1],为写打开。

要关闭管道只需要将这两个文件描述符关闭即可。

示例代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>int main()
{int fd[2];int pid;char *buf = "李思源是GAY";char readbuf[128];//判断if(pipe(fd) == -1){printf("管道创建失败\n");}//创建子进程pid = fork();if(pid<0){printf("进程创建失败\n");}else if(pid>0){printf("this is father process\n");close(fd[0]);//关闭读write(fd[1],buf,strlen(buf));wait();}else{printf("this is child process\n");close(fd[1]);//关闭写read(fd[0],readbuf,100);printf("菊苑703谁是GAY:%s\n",buf);exit(0);}  return 0;
}

二.有名管道(mkfifo)

有名管道依赖于文件系统,是一个特殊的文件,有名管道和普通文件一样,具有存放的路径,文件的权限,和属性。有名管道存放信息在内存中,两个进程结束后就会自动消失。

1.创建有名管道。

使用mkfifo函数创建有名管道,有两个参数。

第一个参数是要创建的管道文件名。

第二个参数是,赋予的权限。

extern int mkfifo(__const char *__path, __mode_t __mode);

使用mkfifo创建的文件,也可以使用读写一般文件的方式去读取。

2.示例代码

read.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include <errno.h>
#include <fcntl.h>int main()
{char buf[30] = {0};if((mkfifo("./fife",0600) == -1)  && errno != EEXIST)//创建管道{printf("mkfifo failuer\n");perror("why");//打印错误}int fd = open("./fife",O_RDNOLY);//以只读的方式打开此文件printf("open fife success\n");int nread =  read(fd,buf,30);//读取文件printf("read is %d  byte.fifo.context:%s\n ",nread,buf);close(fd);//关闭return 0;
}

write.c

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include <errno.h>
#include <fcntl.h>int main()
{char *buf = "siyuan is gay";//写入的数据inr fd;fd = open ("./fife",O_WRONLY);//以只写的方式打开此文件printf("write open fife\n");write(fd,buf,strlen(buf));//写入数据close(fd);//关闭此文件return 0;
}

三.消息队列

消息队列是消息的连接表,存放在内核中,一个消息队列由一个标识符来标识。

进程终止时消息队列里面的内容不会消失。

1.头文件

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

2.创建/访问一个消息队列。

创建/访问消息队列需要使用msgget函数,函数原型如下。

int msgget(key_t key, int msgflag);

参数一.key 需要使用ftok()函数来获取键值。

参数二.msgflag 权限 IPC_CREAT 如果消息队列不存在则创建,存在则打开返回。

IPC_EXCL 如果消息队列不存在则创建,存在则出错。

返回值.失败返回-1,成功返回非负整数

3.添加消息

把消息添加到队列(发送)需要使用msgsnd()函数,函数原型如下。

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  1. msqid 由msgget函数返回的消息队列标识符。

  1. msgp:发送的消息。

  1. msgsz:消息的长度。

  1. msgflg 默认为0;

  1. 成功返回0,失败返回-1.

4.接受消息

从消息队列获取消息(接受)需要使用msgrcv()函数,函数原型如下。

 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
  1. msqid 消息队列标识符

  1. msgp 消息缓冲区

  1. msgsz 接受消息的大小

  1. msgfig 通常为0

4.ftok

通常是将文件的索引节点取出,然后在前面加上子序号就得到key_t的值。

key_t ftok(const char*pathname,int id);

6.删除队列

从内核中删除msgqid标识的消息队列使用msgctl()函数,原型如下。

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

参数一为消息队列标识符

参数二为指令,通常用IPC_RMID

6.示例代码

msgGet.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>struct msgbuf
{long mtye;char mtext[100];
};int main()
{struct msgbuf getbuf;int msgid;//创建一个消息队列,key_t key;key = ftok(".",20)printf("key::%x",key);int msgid = msgget(key,IPC_CREAT|0777);//msgget返回-1,创建失败。if(msgid == -1){printf("fail\n");}//接收数据msgrcv(msgid,&getbuf,sizeof(getbuf.mtext),888,0);printf("juyuan 703 de gay is:%s",getbuf.mtext);msgctl(msgid,IPC_EMID,NULL);return 0;
}

msgSend.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdlib.h>
#include<stdio.h>
struct msgbuf
{long mtye;//消息类型>0char mtext[100];//文本,随便写多少字节都可以
};int main()
{struct mtye sendbuf = {888,"siyua  is GAY"};int msgid;key_t key;key = ftok(".",20)printf("key::%x",key);msgid = msgget(key,IPV_CREAT|0777);if(msgid == -1){printf("fail");}msgsnd(msgid,&sendbuf,strlen(sendbuf.mtext),0);msgctl(msgid,IPC_EMID,NULL);return 0;
}

四.共享内存

共享内存就是允许两个不相关的进程访问同一块逻辑内存。

简单来说就类似于一个桌子,桌子上面写的内容我写的时候你就可以直接看到。

共享内存基本使用:

1.头文件

#inlcude<sys/ipc.h>
#include<sys/shm.h>

2.创建共享内存

要使用共享内存首先要使用shmget()函数来创建一块内存,shmget()函数的原型如下。

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

第一个参数 key_t key :通过使用ftok()函数来获取。

第二个参数 size_t size:创建内存的大小。

第三个参数 int shmfig:权限,比如IPC_CREAT 创建一块内存。

shmget的返回值为一个标识符。

3.挂载共享内存

函数原型如下。

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

参数一 shmid:为shmget()函数返回的标识符。

参数二 shmaddr:为要关联的内存地址,一般传入0,系统会自动匹配一块内存。

4.卸载挂载内存。

当进程不需要共享内存时使用shmdt()函数,该函数不会删除共享内存,只是将该进程脱离,函数原型如下。

int shmdt(const void *shmaddr);

参数为shmget()函数的返回值。

5.释放共享内存

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

参数一为shmget()函数的返回值。

参数儿为执行的命令,IPC_RMID 为删除共性内存。

6.示例代码

shmw.c

#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<string.h>int main()
{int shmid;char * shmaddr;key_t key;key = ftok(".",1);//创建共享内存,权限可读可写shmid = shmget(key,1024*4,IPC_CREAT|0600);//判断是否创建成功if(shmid == -1){printf("shmget fail\n");}//挂载共享内存shmaddr = shmat(shmid,0,0);printf("shmat ok");//将内容拷进共享内存中strcpy(shmaddr,"siyuan is gay");sleep(5);//卸载挂载点shmdt(shmaddr);return 0;
}

shmr.c

#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<string.h>
int main()
{int shmid;char *shmaddr;key_t key;key = ftok(".",1)shmid = shmget(key,1024*4,IPC_CREAT|0600);if(shmid == -1){printf("creat fail\n");exit(-1);}shmaddr = shmat(shmid,0,0);printf("shmget succese\n");//直接打印共享内存的内容printf("data = \s\n",shmaddr);shmdt(shmid);printf("quit");shmctl(shmid,IPC_RMID,0);return 0;
}

五.信号

信号是进程之间相互传递消息的一种方法,信号被称为软中断信号,也可以成为软中断。例如ctrl+c用来中断程序。

2.头文件

 #include <signal.h>

3.函数原型

sighandler_t signal(int signum,sighangler_t handler);

参数一:为处理的信号 ,可以使用kill -l,在中断查看。

参数二:信号的操作,处理方式,可以取以下3种

  1. SIG_IGN 忽略信号

  1. SIG_DFL 恢复对信号的默认处理。

  1. sighandler_t类型的函数指针 handler必须在使用signal前进行声明。

4.信号高级(sigaction)

为什么要有高级版的信号呢?

使用signal虽然完成了信号的收发,但是不能携带数据,这就出现了信号高级版,

信号高级版可以携带一些信息

sigaction函数原型

int sigaction(int signum,const struct sigaction *act, struct sigaction *oldact);
//参数一为操作的信号。
//参数二下面的结构体
//参数三为备份struct sigaction {void       (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作void       (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额外数据和sigqueue配合使用sigset_t   sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值。int        sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据};
//注意!!!!sa_handler、sa_sigaction只能任选其一

5.示例代码

接受端。

#include<signal.h>
#include<stdio.h>void handler(int signum,siginfo_t info*,context)
{    printf("get signum == %d\n",signum);if(context != NULL){    printf("get data == %d\n",info->si_int);printf("from == %d\n",info->si_pid);printf("思源是GAY\n");}}
int main()
{    struct sigaction set;set.sa_sigaction = handler;set.sa_flags = SA_SIGINFO;printf("pid == %d\n",getpid());//打印自己的pid号sigaction(SIGINT,&set,NULL);        while(1);return 0;
}

发送端

#include<signal.h>
#include<stdio.h>int main(int argc,char **argv[])
{int signum;int pid;union sigval value;value.sival_int = 100;signum = atoi(argv[1]);//将信号转换成整型。pid = atoi(argv[2]);//将pid转换成整型。sigqueue(pid,signum,value)printf("done\n");printf("思源是GAY\n");printf("pid == %d\n",getpid());return 0;
}

六.信号量

信号量其实就类似于钥匙,为了防止资源争夺混乱,可以对资源进行上锁,有钥匙的进程访问,没有钥匙则等待。

1.创建/访问信号量(semget)

它的作用是创建一个信号量或者打开一个信号量函数原型如下。

int semget(key_t key, int num_sems, int sem_flags);

参数一key 为ftok函数获取的键值。

参数二num_sems为信号数目,通常都是1.

参数三 为权限,可以使用IPC_CREAT 来创建信号量。

2.修改信号量(semop)

控制修改信号量里面的值

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

参数一为semget返回的标识符

参数二为一个结构体,如下。

struct sembuf{short sem_num; // 除非使用一组信号量,否则它为0short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,// 一个是+1,即V(发送信号)操作。short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,// 并在进程没有释放该信号量而终止时,操作系统释放信号量
};

3.控制信号量(semctl)

控制信号量里面的信息,函数原型如下。

int semctl(int sem_id, int sem_num, int command, ...);

前两个参数与semget一样,第三个参数通常是,SETVAL,IPC_RMID,两个其中一个,使用SETVAL需要第四个参数,通常改变 val的值来设置信号量第一次使用时候的值。


union semun{int val;struct semid_ds *buf;unsigned short *arry;
};

4.示例代码:信号量控制子进程先运行。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include<stdio.h>struct sembuf{short sem_num; // 除非使用一组信号量,否则它为0short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,// 一个是+1,即V(发送信号)操作。short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,// 并在进程没有释放该信号量而终止时,操作系统释放信号量
};void P(int id)//拿出钥匙
{struct sembuf value;value.sem_num = 0;value.sem_op = -1;value.sem_flg = SEM_UNDO;semop(id,&value,1);printf("get key\n");  }void V(int id)//放回钥匙
{struct sembuf set;set.sem_num = 0;set.sem_op = 1;set.sem_flg = SEM_UNDO; semop(id,&set,1);printf("put key\n");
}int main()
{int semid;key_t key;key =ftok(".",1);semid = semget(key,1,IPC_CREAT|0666);//创建信号量union semun initsem;initsem.val = 0;//信号量第一次为0semctl(semid,0,SETVAL,initsem);int pid = fork()if(pid > 0){//父进程阻塞在这无法运行等待子进程将钥匙放进去。P(semid);//父进程的到钥匙printf("this is father\n");V(semid);//放回钥匙cenctl(semid,0,IPC_RMID);//销毁钥匙}else if(pid == 0){printf("this is child\n")V(semid);//子进程先放钥匙}else{printf("fork error\n");}return 0;
}

5.信号量与共享内存结合使用

信号量与共享内存写端

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include<stdio.h>struct sembuf{short sem_num; // 除非使用一组信号量,否则它为0short sem_op;  // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,// 一个是+1,即V(发送信号)操作。short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,// 并在进程没有释放该信号量而终止时,操作系统释放信号量
};void P(int id,int num)//拿出钥匙
{struct sembuf value;value.sem_num = num;value.sem_op = -1;value.sem_flg = SEM_UNDO;semop(id,&value,1);printf("get key\n");  }void V(int id,int num)//放回钥匙
{struct sembuf set;set.sem_num = num;set.sem_op = 1;set.sem_flg = SEM_UNDO; semop(id,&set,1);printf("put key\n");
}int main()
{int semid;int shmid;char *shmaddr;key_t key;key_t key1;key =ftok(".",1);//获取建值key1 = ftok(".",2);semid = semget(key,1,IPC_CREAT|0666);//创建信号量shmid = shmget(key1,1024*4,IPC_CREAT|0666);//创建共享内存union semun initsem;initsem.val = 0;//信号量第一次为0semctl(semid,0,SETVAL,initsem);P(semid,0);shmaddr  = shmat(shmid,0,0);strcpy(shmaddr,"si yuan is gay");shmdt(shmaddr);

Linx进程间通信(IPC)和基本操作。相关推荐

  1. Linux进程+进程间通信IPC

    一 Linux进程 1) 进程的内存映像 2)解释 BSS段:在采用段式内存管理的架构中,BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Bloc ...

  2. 进程间通信 IPC、LPC、RPC

    原文请见:进程间通信IPC.LPC.RPC 进程间通信(IPC,Inter-Process Communication),指至少两个进程或线程间传送数据或信号的一些技术或方法.进程是计算机系统分配资源 ...

  3. 详解操作系统之进程间通信 IPC (InterProcess Communication)

    进程间通信(IPC,Inter-Process Communication),指至少两个进程或线程间传送数据或信号的一些技术或方法. 进程是计算机系统分配资源的最小单位(严格说来是线程).每个进程都有 ...

  4. Android中进程间通信(IPC)方式总结

    IPC为进程间通信或跨进程通信,是指两个进程进行进程间通信的过程.在PC和移动设备上一个进程指的是一个程序或者一个应用,所以我们可以将进程间通信简单理解为不同应用之间的通信,当然这种说法并不严谨. 在 ...

  5. 漫谈QNX(架构/进程,线程,同步,进程间通信IPC)

    (1)架构 说起Blackberry的QNX操作系统, 想必大家都听说过,但到底为什么QNX能如此有名?难道微软的Windows和Linux都不能与之抗衡? 美国NASA的太空接驳飞船也使用QNX操作 ...

  6. linux:进程间通信 IPC

    文章目录 1.管道 1.1.匿名管道 1.2.有名管道 2.信号 3.共享内存 3.1.共享内存接口 3.1.1.生成 key 值 3.1.2.创建共享内存 3.1.3.创建共享内存映射 3.1.4. ...

  7. Linux系统编程学习笔记(九)进程间通信IPC

    进程间通信IPC: 我们以前介绍过进程控制原语,看到怎么创建多个进程.但是进程之间交互信息的方式只介绍了通过fork或者exec继承父进程的打开文件或者通过文件系统. 经典的进程通信方式有:管道.FI ...

  8. linux进程间通信 ipc,进程间通信IPC (InterProcess Communication)

    一.进程间通信的概念 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区, ...

  9. 进程间通信IPC、LPC、RPC

    IPC是进程间通信,有两种,它们是LPC和RPC,前者是本地过程调用 后者是远程过程调用 简介 进程间通信(IPC,Inter-Process Communication),指至少两个进程或线程间传送 ...

最新文章

  1. [Java开发之路](23)装箱与拆箱
  2. 数据库多对多设计方案(贴标签的设计方案)
  3. HTML常见小问题2
  4. 【Python】特征工程:数值特征的缩放与编码
  5. leetcode 530. 二叉搜索树的最小绝对差(Java版)
  6. 用Thread实现socket多线通讯
  7. hibernate annotation注解方式来处理映射关系
  8. Linux+Tomcat建站笔记(JDK,Mysql,Vsftpd,Iptables等配置)
  9. ‘dict’ object has no attribute 'has_key'
  10. 【scala初学】scala IDE eclipse
  11. linux中的帮助命令man(manual 手册,帮助,指南)
  12. 印象笔记再WIN10同步失败解决方法
  13. R Markdown与RStudio IDE深度结合
  14. Android studio打包apk
  15. 移动硬盘上安装Windows 10系统
  16. tensorflow 张量
  17. 偏微分方程数值解程序设计与实现——数学基础
  18. 比较热门的物联网服务器的使用
  19. 进销存mysql数据库_进销存管理系统数据库设计
  20. elasticsearch怎么实现拼音首字母查询

热门文章

  1. JS 是怎样运行起来的
  2. 泉州师范学院计算机课程表,泉州师范学院软学院 2010 级第 四 学期课程表.doc
  3. 影像去除黑边或白边的三种方法
  4. java递归兔子_兔子问题 —— 递归的应用
  5. 设计模式案例代码之适配器模式
  6. 家庭消费类摄像头选择攻略和隐私保护小建议
  7. 服务器机房监控系统研究,机房环境及服务器运行状态的嵌入式监控系统设计
  8. 企业如何通过会员积分营销留住客户?
  9. 【小米oj】 小米兔跳格子
  10. 【Unity小游戏】《捕鱼达人》小游戏来啦~ 有源码下载【文末送书】