【Linux 进程间通信】管道和共享内存

本文介绍了进程间通信的三种常见方法:匿名管道,包括其特点如单向通信、文件性质和同步机制;命名管道,与匿名管道类似但可应用于任何进程;以及共享内存,强调其高效性并展示了创建、删除和使用共享内存的示例代码。通过这些机制,进程可以实现数据的高效传输和协作。
摘要由CSDN通过智能技术生成

1.进程间通信的概念

2.匿名管道

匿名管道的5个特点

  1. 管道是一个单向通信的通信信道;

  1. 匿名管道作用与具有血缘关系的进程,常用于父子进程;

  1. 管道是一个文件,生命周期随进程;

  1. 管道自带同步机制、原子性;

  1. 管道是面向字节流;

管道的4种结果

  1. 读端快且写端慢或者不写,读端要等待写端;

  1. 写端快且读端慢或者不读,写端要等待读端;

  1. 读端关闭,写端收到SIGPIPE信号直接终止

  1. 写端关闭,读端读完pipe内部的数据,然后再读会返回0,表明已经读到文件结尾;

pipe函数

#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main()
{
    int pipefd[2]={0};//创建匿名管道
    if(pipe(pipefd)!=0)
    {
        perror("pipe error!\n");
        exit(1);
    }
    if(fork()==0)//创建子进程
    {
        close(pipefd[0]);//子进程关闭读
        const char* message="hello world\n";
        while(1)
        {
            write(pipefd[1],message,strlen(message));
            sleep(1);
        }
        exit(1);
    }
    close(pipefd[1]);//父进程关闭写
    while(1)
    {
        char* buffer[64];
        ssize_t s=read(pipefd[0],buffer,sizeof(buffer)-1);
        if(s==0)//s==0说明写端关闭,且读端把内容读完
        {
            printf("子进程关闭写入\n");
            break;
        }
        else if(s>0)
        {
            buffer[s]=0;
            printf("child say to father:%s",buffer);
        }
        else
        {
            printf("读取失败\n");
            break;    
        }
    }
    return 0;
}

执行结果

原理

3.命名管道

命名管道的情况和特点和匿名管道相同,但是命名可以运用到任意进程

mkfifo函数

server.c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define MYFIFO "./myfifo"

int main()
{
    umask(0);//把umask设置0
    if(mkfifo(MYFIFO,0666)<0)
    {
        perror("mkfifo fail\n");
        exit(1);
    }
    int fd = open("myfifo",O_RDONLY);//服务器端以读方式打开文件
    if(fd<0)
    {
        perror("open fail\n");
        exit(2);
    }
    while(1)
    {
        char buffer[64];
        ssize_t s=read(fd,buffer,63);//read返回值读取的字节数
        if(s>0)
        {
            buffer[s]=0;
            if(strcmp(buffer,"ls")==0)//输入ls就进程替换ls -l命令
            {
                execlp("ls","ls","-l",NULL);
                return(1);
            }
            else
                printf("client say to server:%s\n",buffer);
        }
        else if(s==0)
        {
            printf("client close");
            break;
        }
        else
        {
            printf("read fail");
            break;
        }
    }
    return 0;
}

client.c

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<fcntl.h>
#define MYFIFO "./myfifo" 

int main()
{
    int fd=open(MYFIFO,O_WRONLY);//用户端以写的方式打开管道文件
    if(fd<0)
    {
        perror("open\n");
        return 1;
    }
    while(1)
    {
        char message[64];
        printf("please enter:");
        fflush(stdout);//刷新标准输出流
        ssize_t s=read(0,message,63);//从键盘读
        message[s]=0;
        write(fd,message,strlen(message)-1);//写到管道文件的缓冲区
    }
    return 0;
}

进程使用管道通信,不会把内容写到磁盘中去,会在缓冲区中读写;

4.共享内存

共享内存的效率是最高的因为它是使用直接虚拟地址映射来写入和读写数据的,不像管道需要使用read和write来读写

4.1共享内存的创建

shmget和ftok接口

#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdio.h>

#define PATHNAME "./"
#define PROJID 0x5555
int main()
{
    key_t key=ftok(PATHNAME,PROJID);//获取一个唯一key值
    int shmid=shmget(key,4096,IPC_CREAT);//创建共享内存

    printf("key:%d,shmid:%d\n",key,shmid);
    return 0;
}

创建共享内存,程序执行完毕不会被OS回收

4.2删除共享内存

命令行:

代码:

    shmctl(shmid,IPC_RMID,NULL);//删除共享内存

4.3进程连接到共享内存(shmat),去关联(shmdt)

4.4简单使用共享内存通信

clien.c

#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#define PATHNAME "./"
#define PROJID 0x5555

int main()
{
    key_t key=ftok(PATHNAME,PROJID);
    int shmid=shmget(key,4096,IPC_CREAT|0666);
    char* mem=shmat(shmid,NULL,0);//关联
    printf("client process attaches success\n");
    while(1)//打印共享内存的内容
    {
        printf("%s\n",mem);
        sleep(1);
    }
    shmdt(mem);//去关联
    return 0;
}

server.c

#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#define PATHNAME "./"
#define PROJID 0x5555
int main()
{
    key_t key=ftok(PATHNAME,PROJID);
    int shmid=shmget(key,4096,IPC_CREAT|0666);//创建一个共享内存并初始化权限为0666;
    if(shmid<0)
    {
        perror("shmget\n");
        return 1;
    }
    char* mem=(char*)shmat(shmid,NULL,0);//关联
    printf("server process attaches success\n");
    char i='a';
    while(i<='z')//往共享内存写入数据
    {
        mem[i-'a']=i;
        i++;
        mem[i-'a']=0;
        sleep(2);
    }
    shmdt(mem);//去关联
    printf("server process detach success\n");
    shmctl(shmid,IPC_RMID,NULL);//关闭共享内存
    printf("shared memory close\n");
    return 0;
}

执行结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值