管道通信原理(学习笔记)

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、streams等。其中Socket和Streams支持不同主机上的两个进程IPC.
管道的创建
管道是由调用pipe函数来创建

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

fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。

管道如何实现进程间的通信
(1)父进程创建管道,得到两个⽂件描述符指向管道的两端

(2)父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。

(3)父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。

一、管道
管道,通常指无名管道,是 UNIX 系统IPC最古老的形式。

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <errno.h>
  5 
  6 //       int mkfifo(const char *pathname, mode_t mode);
  7 
  8 
  9 int main()
 10 {
 11         if((mkfifo("./file",0600) == -1) && errno == EEXIST){
 12                 printf("create file field\n");
 13                 perror("why");
 14         }
 15 
 16         return 0;
 17 }

二、FIFO
FIFO,也称为命名管道,它是一种文件类型。

	#include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <errno.h>
  5 #include <unistd.h>
  6 #include <fcntl.h>
  7 
  8 
  9 //       int mkfifo(const char *pathname, mode_t mode);
 10 
 11 
 12 int main()
 13 {
 14         char buf[30];
 15 
 16 
 17         if((mkfifo("./file",0600) == -1) && errno != EEXIST){
 18                 printf("create file field\n");
 19                 perror("why");
 20         }
 21 
 22         int fd = open("./file",O_RDONLY);
 23         printf("open successful\n");
 24 
 25         int nread = read(fd,buf,30);
 26         printf("read %d byte,context %s\n",nread,buf);
 27 
 28         close(fd);
 29         return 0;
 30 }

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <errno.h>
  5 #include <unistd.h>
  6 #include <fcntl.h>
  7 #include <string.h>
  8 
  9 
 10 
 11 int main()
 12 {
 13         char *buf="write successful";
 14 
 15 
 16 
 17         int fd = open("./file",O_WRONLY);
 18         printf("write successful\n");
 19 
 20         int nwrite = write(fd,buf,strlen(buf));
 21         printf("read %d byte,context %s\n",nwrite,buf);
 22 
 23         close(fd);
 24         return 0;
 25 }

三、消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。

 1 #include <sys/types.h>
  2 #include <sys/ipc.h>
  3 #include <sys/msg.h>
  4 #include <stdio.h>
  5 
  6 //       int msgget(key_t key, int msgflg);
  7 //int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  8 
  9 //ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
 10 struct msgbuf {
 11           long mtype;       /* message type, must be > 0 */
 12           char mtext[128];    /* message data */
 13 };
 14 
 15 
 16 int main()
 17 {
 18         struct msgbuf sendBuf = {888,"this is msgget from quen"};
 19 
 20         struct msgbuf readBuf;
 21 
 22         key_t key;          //huo qu jian zhi
 23         key = ftok(".",'z'); //"."(dangqianmulu),'z'(limiankeyiweirenyizhi)
 24 
 25         int msgID = msgget(key,IPC_CREAT|0777);
 26 
 27         if(msgID == -1){
 28 
 29                 printf("create msgID filed\n");
 30         }
 31 
 32         msgsnd(msgID,&sendBuf,sizeof(sendBuf.mtext),0);
 33 
 34         msgrcv(msgID,&readBuf,sizeof(readBuf.mtext),988,0);
 35         printf("return read context %s\n",readBuf.mtext);
 36         msgctl(key,IPC_RMID,NULL);   //guan diao dui lie
 37 
 38         return 0;
 39 }


 1 #include <sys/types.h>
  2 #include <sys/ipc.h>
  3 #include <sys/msg.h>
  4 #include <stdio.h>
  5 
  6 //       int msgget(key_t key, int msgflg);
  7 //int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  8 
  9 //ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
 10 struct msgbuf {
 11           long mtype;       /* message type, must be > 0 */
 12           char mtext[128];    /* message data */
 13 };
 14 
 15 
 16 int main()
 17 {
 18         struct msgbuf readBuf;
 19         key_t key;
 20         key = ftok(".",'z');
 21 
 22         int msgID = msgget(key,IPC_CREAT|0777);
 23 
 24 
 25         if(msgID == -1){
 26 
 27                 printf("create msgID filed\n");
 28         }
 29 
 30         msgrcv(msgID,&readBuf,sizeof(readBuf.mtext),888,0);
 31         printf("read context %s\n",readBuf.mtext);
 32 
 33         struct msgbuf sendBuf= {988,"think recive"};
 34         msgsnd(msgID,&sendBuf,sizeof(sendBuf.mtext),0);
 35         msgctl(key,IPC_RMID,NULL);
 36 
 37         return 0;
 38 }


四、共享内存编程
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。

1 #include <sys/shm.h>
2 // 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
3 int shmget(key_t key, size_t size, int flag);
4 // 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
5 void *shmat(int shm_id, const void *addr, int flag);
6 // 断开与共享内存的连接:成功返回0,失败返回-1
7 int shmdt(void *addr); 
8 // 控制共享内存的相关信息:成功返回0,失败返回-1
9 int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
  1 #include <sys/ipc.h>
  2 #include <sys/shm.h>
  3 #include <sys/types.h>
  4 #include <stdio.h>
  5 #include <string.h>
  6 #include <stdlib.h>
  7 #include <unistd.h>
  8 
  9 //       int shmget(key_t key, size_t size, int shmflg);
 10 
 11 int main()
 12 {
 13         char *shmddr;
 14         int shmID;
 15         key_t key;
 16         key = ftok(".",1);
 17 
 18         shmID = shmget(key,1024*4,0);
 19         if(shmID == -1){
 20 
 21                 printf("create failed\n");
 22                 exit(0);
 23         }
 24         shmddr = shmat(shmID,0,0);
 25 
 26         printf("shmmad ok\n");
 27         printf("data %s\n",shmddr);
 28         shmdt(shmddr);
 29 
 30         printf("quit");
 31         return 0;
 32 }

1 #include <sys/ipc.h>
  2 #include <sys/shm.h>
  3 #include <sys/types.h>
  4 #include <stdio.h>
  5 #include <string.h>
  6 #include <stdlib.h>
  7 #include <unistd.h>
  8 
  9 //       int shmget(key_t key, size_t size, int shmflg);
 10 
 11 int main()
 12 {
 13         char *shmddr;
 14         int shmID;
 15         key_t key;
 16         key = ftok(".",1);
 17 
 18         shmID = shmget(key,1024*4,IPC_CREAT|0666);
 19         if(shmID == -1){
 20 
 21                 printf("create failed\n");
 22                 exit(0);
 23         }
 24         shmddr = shmat(shmID,0,0);
 25 
 26         printf("shmmad ok\n");
 27         strcpy(shmddr,"chujunpeng");
 28         sleep(5);
 29 
 30         shmdt(shmddr);
 31 
 32         shmctl(shmID,IPC_RMID,0);
 33         printf("quit");
 34         return 0;
 35 }

五、信号
入门级:

#include <stdio.h>
  2 #include <signal.h>
  3 
  4 //       typedef void (*sighandler_t)(int);
  5 
  6 //       sighandler_t signal(int signum, sighandler_t handler);
  7 
  8 
  9 void handler(int signum)
 10 {
 11         printf("signum is %d",signum);
 12         switch(signum){
 13 
 14                 case 2:
 15                         printf("SIGINT");
 16                         break;
 17                 case 9:
 18                         printf("SIGKILL");
 19                         break;
 20                 case 10:
 21                         printf("SIGUSR1");
 22                         break;
 23 
 24 
 25         }
 26 }
 27 
 28 
 29 int main()
 30 {
 31 
 32         signal(SIGINT,handler);
 33         signal(SIGKILL,handler);
 34         signal(SIGUSR1,handler);
 35         while(1);
 36         return 0;
 37 }

  1 #include <stdio.h>
  2 #include <signal.h>
  3 #include <sys/types.h>
  4 #include <stdlib.h>
  5 //       typedef void (*sighandler_t)(int);
  6 
  7 //       sighandler_t signal(int signum, sighandler_t handler);
  8 
  9 
 10 
 11 int main(int argc ,char** argv)
 12 {
 13         int signum;
 14         int pid;
 15 
 16         signum = atoi(argv[1]);    //   shi zhifuchuan suoyi atoi jiang int zhuan huan
 17         pid = atoi(argv[2]);
 18 
 19         printf("num = %d,pid = %d\n",signum,pid);
 20 
 21         kill(pid,signum);
 22 
 23         printf("send ok\n");
 24 
 25         return 0;
 26 }

高级:

1 #include <signal.h>
  2 #include <stdio.h>
  3 #include <sys/types.h>
  4 #include <unistd.h>
  5 
  6 //       int sigaction(int signum, const struct sigaction *act,
  7 //                     struct sigaction *oldact);
  8 
  9 // void     (*sa_sigaction)(int, siginfo_t *, void *);
 10 
 11 void handler(int signum,siginfo_t *info,void *context)
 12 {
 13         printf("signum is %d\n",signum);
 14         if(context != NULL){
 15 
 16 
 17                 printf("data is %d\n",info->si_int);
 18 //              printf("data is %d\n",info.si);
 19                 printf("from:%d\n",info->si_pid);
 20 
 21         }
 22 
 23 }
 24 
 25 int main()
 26 {
 27         struct sigaction act;
 28         printf("pid = %d\n",getpid());
 29 
 30         act.sa_sigaction = handler;
 31         act.sa_flags = SA_SIGINFO;
 32 
 33         sigaction(SIGUSR1,&act,NULL);
 34 
 35         while(1);
 36         return 0;
 37 }

  1 #include <signal.h>
  2 #include <stdio.h>
  3 #include <sys/types.h>
  4 #include <unistd.h>
  5 #include <stdlib.h>
  6 //       int sigqueue(pid_t pid, int sig, const union sigval value);
  7 
  8 int main(int argc,char **argv)
  9 {
 10         int signum;
 11         int pid;
 12 
 13         signum = atoi(argv[1]);
 14         pid = atoi(argv[2]);
 15 
 16         union sigval value;
 17         value.sival_int = 100;
 18 
 19         sigqueue(pid,signum,value);
 20         printf("%d,send ok\n",getpid());
 21 
 22 
 23         return 0;
 24 }

六、信号量

#include <sys/types.h>
  2 #include <sys/ipc.h>
  3 #include <sys/sem.h>
  4 #include <unistd.h>
  5 #include <stdio.h>
  6 //       int semget(key_t key, int nsems, int semflg);
  7 //       int semctl(int semid, int semnum, int cmd, ...);
  8 //       int semop(int semid, struct sembuf *sops, size_t nsops);
  9 
 10 union semun {
 11           int              val;    /* Value for SETVAL */
 12           struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
 13           unsigned short  *array;  /* Array for GETALL, SETALL */
 14           struct seminfo  *__buf;  /* Buffer for IPC_INFO
 15                                            (Linux-specific) */
 16 };
 17 
 18 void pGetkey(int id)
 19 {
 20         struct sembuf set;
 21         set.sem_num = 0;
 22         set.sem_op = -1;
 23         set.sem_flg = SEM_UNDO;
 24 
 25         semop(id,&set,1);
 26         printf("get key\n");
 27 }
 28 
 29 
 30 void vPutkey(int id)
 31 {
 32         struct sembuf set;
 33         set.sem_num = 0;
 34         set.sem_op = 1;
 35         set.sem_flg = SEM_UNDO;
 36 
 37         semop(id,&set,1);
 38         printf("put key\n");
 39 }
	
	int main()
 41 {
 42         key_t key;
 43         int semId;
 44 
 45         key = ftok(".",2);
 46                            //信号量集中有一个信号               
 47         semId = semget(key,1,IPC_CREAT|0666);
 48 
 49         union semun initsem;
 50         initsem.val = 0;        //不可以拿锁状态
 51         semctl(semId,0, SETVAL,initsem); //初始化信号量
 52                      //操作第0个信号量 //SETVAL设置信号量的值设置为initsem
 53         int pid = fork();
 54         if(pid > 0){
 55                 pGetkey(semId);
 56                 printf("this is father\n");
 57                 vPutkey(semId);
 58         }
 59 
 60         else if(pid == 0){
 61                  printf("this is children\n");
 62                 vPutkey(semId);
 63         }else{
 64                 printf("error\n");
 65         }
 66 
 67         return 0;
 68 }


特点总结
1.管道:速度慢,容量有限,只有父子进程能通讯

2.FIFO:任何进程间都能通讯,但速度慢

3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题

4.信号量:不能传递复杂消息,只能用来同步

5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值