• 进程间通信的方法和实现


    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.
  • 相关阅读:
    关于根据索引 删除队
    Vs 2012 编译C 语言
    动态绑定 dgvlist 列
    自定义控件闪烁问题
    程序员都不读书,但你应该读
    对于委托的理解 委托和事件
    ​label 中 文字的位置
    vs2010 折叠C/c++中的if
    关于动态创建控件性能提高 以及 SuspendLayout & ResumeLayout 的使用
    c# WinForm开发 DataGridView控件的各种操作总结(单元格操作,属性设置)
  • 原文地址:https://www.cnblogs.com/wang1994/p/5944703.html
Copyright © 2020-2023  润新知