栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

【Linux学习笔记】11-进程通信

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Linux学习笔记】11-进程通信

进程通信

一级目录

二级目录

三级目录 1、管道

1. 匿名管道2. 命名管道 2、共享内存

1. 创建共享内存(`man shmget`)2. 获取唯一性key(`man get`)3. 删除共享内存(`man shmctl`)4. 将进程关联到共享内存/去关联共享内存(`man shmat`)5. 获取共享内存中的内容6. 把内容写入共享内存 3、消息队列

1. 获取消息队列(`man msgget`)2. 删除消息队列(`man msgctl`)

一级目录 二级目录 三级目录 1、管道 1. 匿名管道

匿名管道供具有血缘关系的进程进行通信

匿名管道通信步骤:
1、一个进程分别以读写方式打开同一个文件,这样就有两个文件描述符,一个以read方式指向该文件,一个以write方式指向该文件
2、父进程fork创建一个子进程,因为子进程创建以父进程为模版,则子进程的file_struct的fd_array与父进程一样
3、让父进程read,子进程write,则关闭父进行的write,保持父进程的read打开;关闭子进程的read,保持子进程的write打开

测试1

  1 #include 
  2 #include 
  3 
  4 int main() {
  5     int pipe_fd[2] = {0};
  6     if (pipe(pipe_fd) < 0) {
  7         perror("pipe");
  8         return 1;
  9     }
 10     printf("%d %dn", pipe_fd[0], pipe_fd[1]);                                                                                       
 11     return 0;
 12 }
~


测试2

    1 #include 
    2 #include 
    3 #include 
    4 #include 
    5 #include 
    6 #include 
    7                                                                                                                                    
    8 
    9 int main() {
   10     int pipe_fd[2] = {0};
   11     if (pipe(pipe_fd) < 0) {
   12         perror("pipe");
   13         return 1;
   14     }
   15     printf("%d %dn", pipe_fd[0], pipe_fd[1]);
   16     pid_t id = fork();
   17     if (id < 0) {
   18         perror("fork");
   19     }
   20     if (id == 0) { //write
   21         //child
   22         close(pipe_fd[0]);
W> 23         char *msg = "hello world, i am child process";
   24         int count = 5;
   25         while (count) {
   26             write(pipe_fd[1], msg, strlen(msg));
   27             sleep(1);
   28             count--;
   29         }
   30         close(pipe_fd[1]);
   31         exit(0);
   32     }else {     // read
   33         //parent
   34         close(pipe_fd[1]);
   35         ssize_t size = 0;
   36         char buf[64] = {0};
   37         while(1) {
   38             size = read(pipe_fd[0], buf, sizeof(buf)-1);
   39             if (size > 0) {
   40                 buf[size] = 0;
   41                 printf("parent get message from child#: %sn", buf);
   42             } else if (size == 0) {
   43                 printf("pipe file close, child quit!n");
   44                 break;
   45             }
   46         }
   47         close(pipe_fd[0]);
   48         int status = 0;
   49         pid_t ret = waitpid(id, &status, 0);
   50         if (ret == -1) {
   51             perror("waitpid");
   52             return 1;
   53         }
   54         printf("child is waited, the exit code is %dn", WEXITSTATUS(status));
   55     }
   56     return 0;
   57 }   


测试3:读端不读且关闭了read,写端会怎么样?
系统直接kill了写端,因为没人读,写就是做的无用功,系统不允许任何无用功

#include 
#include 
#include 
#include 
#include 
#include 


int main() {
    int pipe_fd[2] = {0};
    if (pipe(pipe_fd) < 0) {
        perror("pipe");
        return 1;
    }
    printf("%d %dn", pipe_fd[0], pipe_fd[1]);
    pid_t id = fork();
    if (id < 0) {
        perror("fork");
    }
    if (id == 0) { //write
        //child
        close(pipe_fd[0]);
        char *msg = "hello world, i am child process";
        int count = 5;
        while (count) {
            write(pipe_fd[1], msg, strlen(msg));
            sleep(1);
            count--;
        }
        close(pipe_fd[1]);
        exit(0);
    }else {     // read
        //parent
        close(pipe_fd[1]);
        ssize_t size = 0;
        char buf[64] = {0};
        while(1) {
            size = read(pipe_fd[0], buf, sizeof(buf)-1);
            if (size > 0) {
                buf[size] = 0;
                printf("parent get message from child#: %sn", buf);
            } else if (size == 0) {
                printf("pipe file close, child quit!n");
                break;
            }else{
                break;
            }
            close(pipe_fd[0]);
        }
        //close(pipe_fd[0]);
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if (ret == -1) {
            perror("waitpid");
            return 1;
        }
        printf("child is waited, the sig code is %d, the exit code is %dn", (status & 0x7F), WEXITSTATUS(status));
    }
    return 0;
}


管道的生命周期是随着进程的生命周期的,因为一个进程关闭了,则该进程打开的文件也会关闭

2. 命名管道

用于没有血缘关系的两个进程之间的通信
mkfifo:用于创建一个命名管道的命令,mkfifo filename可以只在命令行创建一个名为filename的命名管道文件。
但是,向filename写数据时,我们的数据并不会写到磁盘上,只会写到struct file结构体的缓冲区里。(普通文件需要将数据刷新到磁盘来持久化存储)

测试1:在创建了myfifo的命名管道文件后
在bash1里:

while :; do echo "hello world"; sleep 1; done > myfifo 

在bash2里:

cat < myfifo 

可以看到“hello world”在bash2中被打印出来

测试2:代码级命名管道通信

int mkfifo(const char *filename, mode_t mode)
成功返回0,失败返回-1

创建一个servre,一个client,client发消息,server接收到消息

//server.c
  1 #include "stdio.h"
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 
  9 #define FIFO "./fifo"
 10 
 11 int main() {
 12     int ret = mkfifo(FIFO, 0644);
 13     if (ret < 0) {
 14         perror("mkfifo");
 15     }
 16     int fd = open(FIFO, O_RDONLY);
 17     if (fd < 0) {
 18         perror("open");
 19         return 1;
 20     }
 21 
 22     char buf[64] = {0};
 23 
 24     while (1) {
 25         ssize_t s = read(fd, buf, sizeof(buf)-1);
 26         if (s > 0) {
 27             buf[s] = 0;
 28             printf("parent get message from client#: %s", buf);                                                                      
 29         }else if(s == 0) {
 30             printf("client quitn");
 31             break;
 32         }else {
 33             break;
 34         }
 35     }
 36     close(fd);
 37     return 0;
 38 }
//client.c
  1 #include "stdio.h"
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 
  9 #define FIFO "./fifo"
 10 
 11 int main() {
 12     int fd = open(FIFO, O_WRONLY);
 13     if (fd < 0) {
 14         perror("open");
 15         return 1;
 16     }
 17 
 18     char buf[128];
 19 
 20     while (1) {
 21         printf("please enter# ");
 22         fflush(stdout);
 23         buf[0] = 0;
 24         ssize_t s = read(0, buf, sizeof(buf)-1);                                                                                     
 25         if (s > 0) {
 26             buf[s] = 0;
 27             write(fd, buf, strlen(buf));
 28         }else if(s == 0) {
 29             break;
 30         }else {
 31             break;
 32         }
 33     }
 34     close(fd);
 35     return 0;
 36 }


2、共享内存

不需要read/write等接口读和写,因为已经映射到内存了
共享内存:在物理内存上申请的一段空间,由OS将其分别通过两个进程的页表映射到各自的虚拟内存中(进程双方就看到了同一份资源),然后将地址返回给用户,就可以通过这段空间进行通信。
系统会对所有的共享内存进行管理:先描述再组织

1. 创建共享内存(man shmget)


shmflg后面也可以跟权限:0644,一样的用|分隔

grep -ER ‘IPC_CREAT’ /usr/include/:查看IPC_CREAT
可以看到其定义在vim /usr/include/bits/ipc.h中

2. 获取唯一性key(man get)


只要两个进程ftok参数填一样的,那个获得的返回值key也是一样的,也就能指示同一个共享内存(管理共享内存的struct中存在标识它自己的key字段)

3. 删除共享内存(man shmctl)


在*ctl中可以查看描述其对应资源的结构体(共享内存/消息队列/信号量)

第一个参数为共享内存标识码,第二个参数设置为IPC_RMID表示删除共享内存,最后一个暂时设置为NULL

4. 将进程关联到共享内存/去关联共享内存(man shmat)


第二个参数和第三个参数暂时设为NULL和0

// 用于不断查看共享内存信息
while :; do ipcs -m | head -3 && ipcs -m | grep "xupeng";echo "###########"; sleep 1; done
5. 获取共享内存中的内容

(因为已经通过shmat获得到了虚拟内存的地址,直接像打印buffer也就是数组中的内容一样打印)

6. 把内容写入共享内存

共享内存生命周期随OS
共享内存不提供任何同步互斥,彼此独立
共享内存通信是最快的;没有拷贝到文件中的操作,没有用户态内核态的转换
shim是用户层操作的概念
key是系统表示唯一性

grep -ER ‘struct ipc_perm’ /usr/include/ :查找ipc_perm

3、消息队列 1. 获取消息队列(man msgget)


参数与shmget一样

2. 删除消息队列(man msgctl)


信号的前缀是sem,semget/semctl…
发送消息时的结构体中的类型,可以指定两个进程进行通信,只有发送类型和接收类型一样的才能进行通信(type=0表示任何进程都可以接收这个消息)。

//client.c
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/ipc.h"
#include "sys/msg.h"

#define SIZE 100

struct Buf{
    long type;
    char text[SIZE];
};


int main() {
    key_t key = ftok("/home/xupeng", 10);
    if (key < 0) {
        perror("ftok");
        return 2;
    }

    int msgid = msgget(key, IPC_CREAT | 0644);
    if (msgid < 0) {
        perror("msgid");
        return 2;
    }

    struct Buf bf;
    bzero(&bf, sizeof(bf));
    bf.type = 1;
    bf.text[0] = 0;
    strcpy(bf.text, "hello world");

    msgsnd(msgid, &bf, strlen(bf.text), 1);


    return 0;
}
//server.c
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "unistd.h"
#include "fcntl.h"
#include "sys/ipc.h"
#include "sys/msg.h"

#define SIZE 100

struct Buf{
    long type;
    char text[SIZE];
};


int main() {
    key_t key = ftok("/home/xupeng", 10);
    if (key < 0) {
        perror("ftok");
        return 2;
    }

    int msgid = msgget(key, IPC_CREAT);
    if (msgid < 0) {
        perror("msgid");
        return 2;
    }

    struct Buf bf;

    size_t size = msgrcv(msgid, &bf, SIZE, 1, 0);
    printf("msgrcv return : %d", size);
    bf.text[size] = 0;
    printf("i get meg from client : %sn", bf.text);
    

    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/751205.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号