zoukankan      html  css  js  c++  java
  • Linux下进程间通信

    以下内容仅作为个人记录的参考,但也欢迎读者前来指正。

    现在linux下使用较多的进程间通信方式主要有以下几种:
    1.管道及有名管道(named pipe)。管道用于有亲缘关系进程间通信,有名管道没有亲缘关系限制。
    2.信号(signal):信号是在软件层面对终端机制的一种模拟
    3.消息队列(messagae queue):克服前面的信息量有限的缺点,具有权限限制的功能
    4.共享内存(shared memory):多个进程可以同时访问同一块内存空间,依靠某种同步机制,如互斥锁和信号量。
    5.信号量(semaphore):主要作为进程之间以及同一进程的不同线程之间的同步和互斥手段
    6.套接字(socket)

    1.管道:

    创建管道时,它会创建两个文件描述符fds[0]/fds[1],分别固定为读/写。

    #include<unistd.h>
    
    int pipe(int fd[2]);
    
    成功:返回0
    失败:返回-1
     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 
     5 int main()
     6 {
     7         int pipefd[2];
     8         char buff[] = "hello";
     9         int len = strlen(buff);
    10         char* data;
    11         data = (char*)malloc(len+1);
    12         if(pipe(pipefd)<0)
    13         {
    14                 printf("create pipe error.
    ");
    15                 exit(1);
    16         }
    17         int pid;
    18         pid = fork();
    19         if(pid==0)
    20         {
    21                 close(pipefd[1]);
    22                 sleep(3);
    23                 int readLen = read(pipefd[0],data,(len+1));
    24                 if(readLen>0)
    25                 {
    26                         printf("child recv %d bytes,and data is %s
    ",readLen,data);
    27                         exit(0);
    28                 }
    29 
    30         }
    31         else if(pid>0)
    32         {
    33                 close(pipefd[0]);
    34                 sleep(1);
    35                 int writeLen = write(pipefd[1],buff,len);
    36                 printf("writeLen = %d
    ",writeLen);
    37                 if(writeLen>0)
    38                 {
    39                         printf("parent write %d bytes,and data is %s.
    ",writeLen,buff);
    40                         waitpid(pid,NULL,0);
    41                         exit(0);
    42                 }
    43         }
    44         return 0;
    45 }

    标准流管道:

    使用popen(const char* command,const char* type);
    类似于shell执行command一样。
    type可以是"r",该命令产生输出
    "w",该命令产生输入
    
    成功:返回文件流指针
    失败:返回-1
    pclose(fp);关闭上面产生的文件流
     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<unistd.h>
     4 #include<fcntl.h>
     5 #define BUFSIZE 1024
     6 int main()
     7 {
     8         FILE* fp;
     9         char* cmd = "ps -ef";
    10         char buf[BUFSIZE];
    11 
    12         if((fp = popen(cmd,"r"))==NULL)
    13         {
    14                 printf("popen error.
    ");
    15                 exit(1);
    16         }
    17 
    18         while((fgets(buf,BUFSIZE,fp))!=NULL)
    19         {
    20                 printf("%s",buf);
    21         }
    22         pclose(fp);
    23         exit(0);
    24 }

     输出还不少啊。

    FIFO:

    有名管道:

    使用mkfifo()函数,类似于open()

    #include<sys/types.h>
    #include<sys/state.h>
    
    int mkfifo(const char* filename,mode_t mode);
    
    mode:O_RDONLY/O_WRONLY/O_RDWR/O_NONBLOCK/O_CREAT/O_EXCL
    
    成功返回0,失败返回-1
    
    出错信息:
    EACCESS/EEXIST/ENAMETOOLONG/ENOENT/ENOSPC/ENOTDIR/EROFS

    fifo_read.c

     1 #include<sys/types.h>
     2 #include<sys/stat.h>
     3 #include<errno.h>
     4 #include<fcntl.h>
     5 #include<stdio.h>
     6 #include<stdlib.h>
     7 #include<limits.h>
     8 
     9 #define MYFIFO "/tmp/myfifo"
    10 #define MAX_BUFFER_SIZE PIPE_BUF
    11 
    12 int main()
    13 {
    14         char buf[MAX_BUFFER_SIZE];
    15         int fd;
    16         int nread;
    17 
    18         if(access(MYFIFO,F_OK)==-1)
    19         {
    20                 if((mkfifo(MYFIFO,0666)<0)&&(errno!=EEXIST))
    21                 {
    22                         printf("cannot create fifo file
    ");
    23                         exit(1);
    24                 }
    25         }
    26 
    27         fd = open(MYFIFO,O_RDONLY);
    28         if(fd==-1)
    29         {
    30                 printf("open fifo file error");
    31                 exit(1);
    32         }
    33 
    34         while(1)
    35         {
    36                 memset(buf,0,sizeof(buf));
    37                 if((nread = read(fd,buf,MAX_BUFFER_SIZE))>0)
    38                 {
    39                         printf("read '%s' from fifo
    ",buf);
    40                 }
    41         }
    42         close(fd);
    43         exit(0);
    44 }

    fifo_write.c

     1 #include<sys/types.h>
     2 #include<sys/stat.h>
     3 #include<errno.h>
     4 #include<fcntl.h>
     5 #include<stdio.h>
     6 #include<stdlib.h>
     7 #include<limits.h>
     8 
     9 #define MYFIFO "/tmp/myfifo"
    10 #define MAX_BUFFER_SIZE PIPE_BUF
    11 
    12 int main(int argc,char* argv[])
    13 {
    14         int fd;
    15         char buf[MAX_BUFFER_SIZE];
    16         int nwrite;
    17 
    18         if(argc<=1)
    19         {
    20                 printf("Usage: ./fifo_write string
    ");
    21                 exit(1);
    22         }
    23         sscanf(argv[1],"%s",buf);
    24 
    25         fd = open(MYFIFO,O_WRONLY);
    26         if(fd==-1)
    27         {
    28                 printf("open fifo file error
    ");
    29                 exit(1);
    30         }
    31         if((nwrite=write(fd,buf,MAX_BUFFER_SIZE))>0)
    32         {
    33                 printf("write '%s' to fifo
    ",buf);
    34         }
    35         close(fd);
    36         exit(0);
    37 }

    先启动读程序

     再启动写程序

    信号与信号量暂且跳过,直接看一下共享内存。

    共享内存:
    分为两个步骤。
    (1):创建共享内存 shmget(),从内存获取一段共享内存区域
    (2):映射共享内存 把创建的共享内存映射到具体的进程空间,使用函数shmat()
    撤销映射函数 shmdt()

    shmget()

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    int shmget(key_t key,int size,int shmflg);
    key为共享内存的键值,特殊值IPC_PRIVATE,用于创建当前进程的私有共享内存
    返回-1为出错,否则为共享内存标识符

    shmat()

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    char* shmat(int shmid,const void* shmaddr,int shmflg);
    
    shmflg:
    SHM_RDONLY 只读,0为可读可写
    -1:出错,否则返回被映射的段地址

    shmdt()

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    int shmdt(const void* shmaddr);
    成功返回0,出错返回-1

    shmem.c

      1 #include<sys/types.h>
      2 #include<sys/ipc.h>
      3 #include<sys/shm.h>
      4 #include<stdio.h>
      5 #include<stdlib.h>
      6 #include<string.h>
      7 
      8 #define BUFFER_SIZE 2048
      9 
     10 int main()
     11 {
     12         pid_t pid;
     13         int shmid;
     14         char* shm_addr;
     15         char flag[] = "write";
     16         char buff[BUFFER_SIZE];
     17 
     18         if((shmid = shmget(IPC_PRIVATE,BUFFER_SIZE,0666))<0)
     19         {
     20                 perror("shmget");
     21                 exit(1);
     22         }
     23         else
     24         {
     25                 printf("create shared-memory: %d
    ",shmid);
     26         }
     27         system("ipcs -m");
     28 
     29         pid = fork();
     30         if(pid==-1)
     31         {
     32                 perror("fork");
     33                 exit(1);
     34         }
     35         else if(pid ==0)
     36         {
     37                 if((shm_addr = shmat(shmid,0,0))==(void*)-1)
     38                 {
     39                         perror("child: shmat");
     40                         exit(1);
     41                 }
     42                 else
     43                 {
     44                         printf("child attach shared-memory: %p
    ",shm_addr);
     45                 }
     46                 system("ipcs -m");
     47 
     48                 while(strncmp(shm_addr,flag,strlen(flag)))
     49                 {
     50                         printf("child: wait enable data...
    ");
     51                         sleep(5);
     52                 }
     53 
     54                 strcpy(buff,shm_addr + strlen(flag));
     55                 printf("child: shared-memory :%s
    ",buff);
     56 
     57                 if(shmdt(shm_addr)<0)
     58                 {
     59                         perror("shmdt");
     60                         exit(1);
     61                 }
     62                 else
     63                 {
     64                         printf("child: deattach shared-memory
    ");
     65                 }
     66                 system("ipcs -m");
     67 
     68                 if(shmctl(shmid,IPC_RMID,NULL)==-1)
     69                 {
     70                         perror("child: shmctl(IPC_RMID)
    ");
     71                         exit(1);
     72                 }
     73                 else
     74                 {
     75                         printf("delete shared-memory
    ");
     76                 }
     77                 system("ipcs -m");
     78         }
     79         else
     80         {
     81                 if((shm_addr = shmat(shmid,0,0))==(void*)-1)
     82                 {
     83                         perror("parent: shmat");
     84                         exit(1);
     85                 }
     86                 else
     87                 {
     88                         printf("parent: attach shared-memory: %p
    ",shm_addr);
     89                 }
     90                 sleep(1);
     91                 printf("
    input some string:
    ");
     92                 fgets(buff,BUFFER_SIZE,stdin);
     93                 strncpy(shm_addr+strlen(flag),buff,strlen(buff));
     94                 strncpy(shm_addr,flag,strlen(flag));
     95 
     96                 if((shmdt(shm_addr))<0)
     97                 {
     98                         perror("parent: shmdt");
     99                         exit(1);
    100                 }
    101                 else
    102                 {
    103                         printf("parent: deattach shared-memory
    ");
    104                 }
    105                 system("ipcs -m");
    106                 waitpid(pid,NULL,0);
    107                 printf("finished
    ");
    108         }
    109 }

    运行结果:

    [root@iZmcbceic4fsvzZ file]# gcc shmem.c 
    [root@iZmcbceic4fsvzZ file]# ./a.out 
    create shared-memory: 98307
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 0          root       666        2048       0                       
    0x00000000 32769      root       666        2048       0                       
    0x00000000 65538      root       666        2048       0                       
    0x00000000 98307      root       666        2048       0                       
    
    parent: attach shared-memory: 0x7f399d89e000
    child attach shared-memory: 0x7f399d89e000
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 0          root       666        2048       0                       
    0x00000000 32769      root       666        2048       0                       
    0x00000000 65538      root       666        2048       0                       
    0x00000000 98307      root       666        2048       2                       
    
    child: wait enable data...
    
    input some string:
    hello world
    parent: deattach shared-memory
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 0          root       666        2048       0                       
    0x00000000 32769      root       666        2048       0                       
    0x00000000 65538      root       666        2048       0                       
    0x00000000 98307      root       666        2048       1                       
    
    child: shared-memory :hello world
    
    child: deattach shared-memory
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 0          root       666        2048       0                       
    0x00000000 32769      root       666        2048       0                       
    0x00000000 65538      root       666        2048       0                       
    0x00000000 98307      root       666        2048       0                       
    
    delete shared-memory
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 0          root       666        2048       0                       
    0x00000000 32769      root       666        2048       0                       
    0x00000000 65538      root       666        2048       0                       
    
    finished
    [root@iZmcbceic4fsvzZ file]# 

    消息队列:

    msgget():创建和打开消息队列

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    int msgget(key_t key,int msgflg);
    key和共享内存类似,IPC_PRIVATE
    出错返回-1,否则返回队列ID

    msgsnd():发送消息

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    int msgsnd(int msqid,const void* msgp,size_t msgsz,int msgflg)
    msqid:消息队列的队列ID
    msgp:指向消息结构的指针。
    为一个结构体
    struct msgbuf{
        long mtype;//消息类型
        char msgtext[1];//消息正文
    };
    msgsz:消息正文的字节数
    msgflg:
    IPC_NOWAIT 若消息无法立刻发送,直接返回
    0:阻塞发送直到发送成功
    出错返回-1,否则返回0

    msgrcv():接收消息

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    int msgrcv(int msgid,void* msgp,size_t msgsz,long int msgtype,int msgflg);
    前3个参数,和msgsnd类似。
    msgtype:
    0:接收消息队列中第一个消息。
    >0:接收消息队列中第一个为msgtype的消息
    <0:接收消息中第一个类型值不小于msgtype绝对值,且类型值最小的消息。
    msgflg:
    MSG_ERROR:截断消息长度到不超过msgsz长度
    IPC_NOWAIT:如果消息队列中没有响应类型消息可以接收,立即返回
    0:阻塞接收,直到收到一条符合类型的消息
    返回-1为出错,0为成功。

    msgctl():控制消息队列

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    
    int msgctl(int msgid,int cmd,struct msqid_ds* buf);
    cmd:
    IPC_STAT,读取消息队列的数据结构,并储存再buf指定的地址。
    IPC_SET,设置数据结构中的ipc_perm与
    IPC_RMID:从系统内核中删除消息队列
    出错返回-1,成功返回0

    msgrcv.c

     1 #include<sys/types.h>
     2 #include<sys/ipc.h>
     3 #include<sys/shm.h>
     4 #include<stdio.h>
     5 #include<stdlib.h>
     6 #include<unistd.h>
     7 #include<string.h>
     8 #define BUFFER_SIZE 512
     9 
    10 struct message{
    11         long msg_type;
    12         char msg_text[BUFFER_SIZE];
    13 };
    14 
    15 int main()
    16 {
    17         int qid;
    18         key_t key;
    19         struct message msg;
    20         if((key = ftok(".",'a'))==-1)
    21         {
    22                 perror("ftok");
    23                 exit(1);
    24         }
    25 
    26         if((qid = msgget(key,IPC_CREAT|0666))==-1)
    27         {
    28                 perror("msgget");
    29                 exit(1);
    30         }
    31         printf("open queue %d
    ",qid);
    32 
    33         do{
    34                 memset(msg.msg_text,0,BUFFER_SIZE);
    35                 if(msgrcv(qid,(void*)&msg,BUFFER_SIZE,0,0)<0)
    36                 {
    37                         perror("msgrcv");
    38                         exit(1);
    39                 }
    40                 printf("the message from process %d: %s
    ",msg.msg_type,msg.msg_text);
    41         } while(strncmp(msg.msg_text,"quit",4));
    42 
    43         if((msgctl(qid,IPC_RMID,NULL))<0)
    44         {
    45                 perror("msgctl");
    46                 exit(1);
    47         }
    48         exit(0);
    49 }

    msgsnd.c

     1 #include<sys/types.h>
     2 #include<sys/ipc.h>
     3 #include<sys/shm.h>
     4 #include<stdio.h>
     5 #include<stdlib.h>
     6 #include<unistd.h>
     7 #include<string.h>
     8 #define BUFFER_SIZE 512
     9 
    10 struct message{
    11         long msg_type;
    12         char msg_text[BUFFER_SIZE];
    13 };
    14 
    15 int main()
    16 {
    17         int qid;
    18         key_t key;
    19         struct message msg;
    20         if((key = ftok(".",'a'))==-1)
    21         {
    22                 perror("ftok");
    23                 exit(1);
    24         }
    25 
    26         if((qid = msgget(key,IPC_CREAT|0666))==-1)
    27         {
    28                 perror("msgget");
    29                 exit(1);
    30         }
    31         printf("open queue %d
    ",qid);
    32 
    33         while(1)
    34         {
    35                 printf("enter some message to the queue:
    ");
    36                 if((fgets(msg.msg_text,BUFFER_SIZE,stdin))==NULL)
    37                 {
    38                         puts("no message");
    39                         exit(1);
    40                 }
    41                 msg.msg_type = getpid();
    42                 if((msgsnd(qid,&msg,strlen(msg.msg_text),0))<0)
    43                 {
    44                         perror("message posted.");
    45                         exit(1);
    46                 }
    47                 if(strncmp(msg.msg_text,"quit",4)==0)
    48                 {
    49                         break;
    50                 }
    51         }
    52         exit(0);
    53 }

  • 相关阅读:
    如何利用c++读取.doc文档
    C++经典面试题(验证你的C++水准)
    与你初识
    VS2005发布项目
    请教一:OpenGL旋转
    数据备份和故障修复文件历史记录
    数据备份和故障修复备份与还原
    使用Windows 8 的“任务计划”令HydraVision更加精彩
    Windows 恢复环境(Windows RE模式)
    Unsupported major.minor version 49.0错误处理
  • 原文地址:https://www.cnblogs.com/dayq/p/15362679.html
Copyright © 2011-2022 走看看