进程间通信的方法和实现

linux 中进程通信实现
通信方式:管道 消息队列 共享内存 信号量 套接口
1.管道
  包括无名管道和有名管道,前者用于父子进程的通信,后者用于运行于同一台
机器上的任意两个进程间的通信。
  1)无名管道
    创建:#include<unistd.h>
       int pipe(int pipefd[2])
       参数:pipefd[0]为读而打开,pipefd[1]为写而打开。
       例:

          #include<unistd.h>
          #include<sys/types.h>
          #include<stdio.h>
          #include<stdlib.h>
          #include<string.h>
          void main()
          {
                int pidfd[2];
                char buf[256];
                int    fd=pipe(pidfd);
                if(fd<0)
                {
                    printf("pipe error
");
                    exit(-1);
                }
                pid_t pid;
                if((pid=fork())==-1)
                {
                    printf("error fork
");
                    exit(-1);
                }
                if(pid == 0)
                {
                    printf("I am child process!
");
                    close(pidfd[0]);
                    write(pidfd[1],"hello ipc",strlen("hello ipc")+1);
                    exit(0);
                }
                else
                {
                    printf("I am father process!
");
                    close(pidfd[1]);
                    read(pidfd[0],buf,sizeof(buf));
                    printf("%s
",buf);
                }
           }

      说明:关闭打开管道,只是相对于自己的进程号来看的。
      但是系统创建的管道,由于字节是依赖于系统定义的,使用流管道,就会突破系统
      的限制。
      讲解函数:

      例:

              #include<stdio.h>
              #include<unistd.h>
              #include<stdlib.h>
              #include<fcntl.h>
              #define BUFSIZE 1024
              int main()
              {
                FILE *fp;
                char *cmd = "ps -ef";
                char buf[BUFSIZE];
                buf[BUFSIZE]='';
                if((fp = popen(cmd,"r"))==NULL)
                perror("popen");
                while((fgets(buf,BUFSIZE,fp)) != NULL)
                printf("%s",buf);
                pclose(fp);
                return 0;
              }                   

      说明:FILE *popen(const char *command,const char *type),
         int pclose(FILE * stream),个人感觉,就是文件IO差不多
         但是,这样使用了流管道而已。

            

      2)命名管道(FIFO)
      不同祖先的进程之间可以通过命名管道共享数据
      命名管道创建和操作
      命名管道的创建
      #include<sys/types.h>
      #include<sys/stat.h>
      int mkfifo(const char *pathname,mode_t mode);
      创建成功为0 ,出错为-1
      操作步骤:
      1.open
      2.read/write
      3.close
      4.unlink
      int unlink(const char *pathname)
      功能:可以删除文件,包括链接文件。
      向管道写文件进程

        #include<stdio.h>
        #include<fcntl.h>
        #include<errno.h>
        #include<stdlib.h>
        #include<sys/types.h>
        #include<unistd.h>
        typedef struct 
        {
           char name[20];
           int age;
        }person_t;
        void main()
        { 
             int ret = mkfifo("fifo",0644);
             if(ret<0)
             {
               perror("mkfifo");
               exit(-1);
             }
             int fd = open("fifo",O_WRONLY);
             if(fd<0)
             {
               perror("open");
               exit(-1);
             }
             person_t x;
             puts("input name age:");
             scanf("%s%d",x.name,&x.age);
             write(fd,&x,sizeof(x));
             close(fd);
        }
    读管道文件内容
    #include<stdio.h>
    #include<fcntl.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<errno.h>
    #include<unistd.h>
    typedef struct
    {
       char name[20];
       int age;
    }person_t;
    int main(int argc ,char **argv)
    {
         if(argc != 2)
         {
              printf("%s argument!
",argv[0]);
              exit(-1);
         }
         person_t y;
         int fd = open(argv[1],O_RDONLY);
         if(fd<0)
         {
              perror("open");
              exit(-1);
         }
         int ret = read(fd,&y,sizeof(y));
         if(ret<0)
         {
            perror("read");
            exit(-1);
         }
         printf("name :%s age : %d
",y.name,y.age);
         close(fd);
         unlink(argv[1]);
    }
    说明:运行的时候,两个进程同时运行。

2.消息队列
  消息队列用于运行于同一台机器上的进程间通信,它和管道很相似,是一个在系统内核中
用来保存消息的队列,它在西戎内核中是以消息链表的形式出现。消息链表中节点的结构用msg
声明。 实例:

 write:
            #include<sys/types.h>
            #include<stdlib.h>
            #include<fcntl.h>
            #include<unistd.h>
            #include<sys/stat.h>
            #include<sys/ipc.h>
            #include<stdio.h>
            typedef struct 
            {
                 long type;
                 char name[20];
                 int age;
             }msg_t;
            int main()
             {
                 key_t key = ftok("/home",'a');
                 int msgid = msgget(key,IPC_CREAT|O_WRONLY|0777);
                 if(msgid<0)
                 {
                     perror("msgget");
                     exit(-1);
                 }
                 msg_t m;
                 puts("input :type name age:");
                 scanf("%ld%s%d",&m.type,m.name,&m.age);
                 msgsnd(msgid,&m,sizeof(m)-sizeof(m.type),0);
                 return 0;

             }    
            read:
                 #include<sys/types.h>
                 #include<sys/types.h>
                 #include<fcntl.h>
                 #include<sys/ipc.h>
                 #include<stdio.h>
                 #include<stdlib.h>
                 typedef struct 
                 {
                   long type;
                   char name[20];
                   int age;
                 }msg_t;
                 int main()
                 {
                      key_t key = ftok("/home",'a');
                      int msgid = msgget(key,O_RDONLY);
                         if(msgid<0)
                      {
                            perror("msgid");
                              exit(-1);
                         }
                      msg_t m;
                      puts("input :type");
                      scanf("%ld",&m.type);
                      printf("m.type:%d
",m.type);
                      msgrcv(msgid,&m,sizeof(m)-sizeof(m.type),m.type,0);
    
                      printf("name:%s age:%d
",m.name,m.age);
                      return 0;
                 }    
            说明:两个程序必须同时启动,要不然接收不到msg,创建和使用消息队列的基本步骤总结,
                  发送端:1.ftok           接收端:1.ftok          必须使用统一类型才能接收到。
                          2.msgsnd                   2.msgrcv

3.共享内存(最快的)
   共享内存时运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间
复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。得到共享内
存有两种方式:

  1).映射/dev/mem 设备
  2).内存映像文件
  此处重点讲一下内存映像文件方式:
  shmget--shmat--shmdt--shmctl
  创建 挂接 解除 删除

write:
     #include<sys/shm.h>
     #include<sys/ipc.h>
     #include<errno.h>
     #include<stdlib.h>
     #include<stdio.h>
     #include<string.h>
     int main()
     {
        key_t key = ftok("/home",'b');
        int shmid = shmget(key,100,IPC_CREAT|0777);
        if(shmid<0)
        {
             perror("shmget");
             exit(-1);
        }
        char *p = (char*)shmat(shmid,NULL,0);
        if(p==(void *)-1)
        {
            perror("shmat");
            exit(-1);
         }
        strcpy(p,"welcome to beijing!");
        shmdt(p);
        return 0;
      }
    说明:一个进程创建内存
         int shmget(key_t key, size_t size, int shmflg);
          挂接 
          void *shmat(int shmid, const void *shmaddr, int shmflg);
          解除
          int shmdt(const void *shmaddr);
          删除
          int shmctl(int shmid, int cmd, struct shmid_ds *buf);
         
    read:
    #include<stdio.h>
    #include<sys/shm.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<errno.h>
    int main()
    {
         key_t key = ftok("/home",'b');
         int shmid = shmget(key,0,0);
         if(shmid<0)
         {
            perror("shmget");
              exit(-1);
         }
         char *p= (char *)shmat(shmid,NULL,SHM_RDONLY);
         if(p==(void*)-1)
         {
            perror("shmat");
            exit(-1);
         }
         puts(p);
         shmdt(p);
         shmctl(shmid,IPC_RMID,NULL);
         return 0;
    }
4.信号
    信号处理三个方式:
                    1.忽略
                    2.捕捉
                    3.默认
    信号登记:
    typedef void (*sighandler_t)(int);
    sighandler_t signal(int signum, sighandler_t handler)
    例:#include<stdio.h>
        #include<string.h>
        #include<signal.h>
        void deal_fun(int signo)
        {
           switch(signo)
           {
             case SIGINT:puts("1");
                         break;
             case SIGTERM:puts("2");
                         break;
             case SIGTSTP:puts("3");
                         break;
             default:puts("4");
                         break;
            }
         }
         int main()
         {
            signal(SIGINT,deal_fun);
            signal(SIGTERM,deal_fun);
            signal(SIGTSTP,deal_fun);
            for(;;)
            {
                write(1,".",1);
                sleep(3);
            }
            return 0;
         }
    
The future's not set,there is no fate but what we make for ourselves.
原文地址:https://www.cnblogs.com/wang1994/p/5944703.html