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

我的物联网之路—Linux中的C编程—进程间通信

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

我的物联网之路—Linux中的C编程—进程间通信

进程间通信

Linux下的进程间通信又称之为ipc 进程间通信可分为:管道、信号、消息队列、共享内存、信号量、套接字

日期变更记录
2021-9-28创建
管道

管道仅存在于内存中,它是一个半双工的通信模型,具有固定的读端和写端,当一个管道建立时,会创建两个文件描述符,分别为fd[0]和fd[1],fd[0]用于读管道,fd[1]用于写管道

无名管道

只能用于具有亲缘关系的进程之间的通信。是一个半双工的通信模式,具有固定的读端和写端,只存在于内存中

1. 父子进程 2. 兄弟进程 有名管道

有名管道可以使互不相关的两个进程实现彼此通信。该管道可以通过路径名来指出,并且在文件系统中是可见的,该管道严格遵守先进先出规则,不支持lseek操作,用户可通过 mknod 管道名 p 来创建有名管道

Example 1. 父子进程
#include 
#include 
#include 
#include 
int main(int argc, char argv[])
{
    int fd[2];
    char rBuf[20];
    int rCnt, wCnt;
    if (pipe(fd) < 0)
    {
        printf("Pipe Create Error ! n");
        exit(1);
    }
    else if ((pipe(fd)==fork()) == 0)
    // 子进程
    {
        close(fd[1]);
        rCnt = read(fd[0], rBuf, sizeof(rBuf));
        if (rCnt < 0)
        {
            printf(" Son Read Error ! n ");
            exit(1);
        }
        else
        {
            printf("Read Success [%d] Content is : %s ", rCnt, rBuf);
        }
        close(fd[0]);
    }
    else
    // 父进程
    {
        close(fd[0]);
        wCnt = write(fd[1], "Hello Son !", sizeof("Hello Son !"));
        if (wCnt < 0)
        {
            printf("Father Write Error ! n");
            exit(1);
        }
        else
        {
            printf("Write Success ! n");
        }
        close(fd[1]);
    }
}
2. 兄弟进程
#include 
#include 
#include 
#include 
#include 
int main(int argc, char argv[])
{
    int fd[2];
    int rCnt, wCnt, ret, ret1;
    char rBuf[20];
    if (pipe(fd) < 0)
    {
        printf("Pipe Create Error ! n");
        exit(1);
    }
    ret = fork();
    if (ret == 0)
    {
        close(fd[1]);
        rCnt = read(fd[0], rBuf, sizeof(rBuf));
        if (rCnt < 0)
        {
            printf(" Son_1 Read Error ! n ");
            exit(1);
        }
        else
        {
            printf("Son_1 Read Success [%d] Content is : %s ", rCnt, rBuf);
        }
        close(fd[0]);
    }
    else
    {
        ret1 = fork();
        if (ret1 == 0)
        {
            close(fd[0]);
            wCnt = write(fd[1], "Hello Son !", sizeof("Hello Son !"));
            if (wCnt < 0)
            {
                printf("Son_2 Write Error ! n");
                exit(1);
            }
            else
            {
                printf("Son_2 Success ! n");
            }
            close(fd[1]);
        }
        else
            // 父进程
        {
            close(fd[0]);
            close(fd[1]);
            waitpid(ret, NULL, 0);
            waitpid(ret1, NULL, 0);
        }
    }
}
3. 有名管道
// r.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char *argv[])
{
    int fd, rCnt;
    char rBuf[20] = {0};
    if((mkfifo("/opt/myfifo", O_RDWR|O_CREAT) < 0) && (errno != EEXIST))
    // 在opt下建立一个有名管道myfifo,判断是否建立成功
    {
        perror("mkfifo:");
        exit(0);
    }
    fd = open("/opt/myfifo", O_RDONLY);
    // 以只读的方式打开管道
    if(fd < 0)
    {
        perror("open:");
    }
    rCnt = read(fd, rBuf, 20);
    // 读取管道内容存放在rBuf中
    printf("read(%d):%s", rCnt, rBuf);
    close(fd);
    return 0;
}
// w.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char *argv[])
{
    int fd;
    if((mkfifo("/opt/myfifo", O_RDWR|O_CREAT) < 0) && (errno != EEXIST))
    // 在opt下建立一个有名管道myfifo,判断是否建立成功
    {
        perror("mkfifo:");
        exit(0);
    }
    fd = open("/opt/myfifo", O_WRONLY);
    // 以只写的方式打开管道
    if(fd < 0)
    {
        perror("open:");
    }
    if(argc == 1)
    {
        printf("请传递要写入管道的值n");
        exit(1);
    }
    else
    {
        write(fd, argv[1], strlen(argv[1]));
        printf("write(%d):%s", (int)strlen(argv[1]), argv[1]);
    }
    close(fd);
    return 0;
}
信号

信号可以直接进行用户空间和内核进程之间的交互,如果一个信号被阻塞,那么该信号会被延迟,直到非阻塞才会被传递给进程

#include 
#include 
#include 
#include 
#include 
void sig_killRaise()
{
    int ret;
    int sigFlag;
    ret = fork();
    if (ret < 0)
    {
        perror("fork:");
        exit(0);
    }
    else if (ret == 0) //子进程
    {
        printf("I am son!n");
        while (1)
        {
            printf("helpn");
            sleep(1);
        }
        printf("son endn");
    }
    else //父进程
    {
        printf("I am you fa !n");
        sleep(5);
        sigFlag = kill(ret, SIGKILL);
        if (sigFlag == 0)
        {
            waitpid(ret, NULL, 0);
        }
        else
        {
            perror("kill:");
        }
    }
}
void fun(int sig_no)
{
    printf(" i am here");
    if (sig_no == SIGINT)
    {
        printf("get ctrl + cn");
    }
}
int main(int argc, char *argvp[])
{
    printf("signal start!n");
    sig_killRaise();
    signal(SIGINT, fun);
}
共享内存

共享内存是一种最为高效的进程间通信方式。总体可分为三部分,第一部分是创建共享内存,第二步是映射共享内存,第三步是撤销映射的操作

//w.c
// 创建共享内存
// 映射共享内存
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    // 创建共享内存
    int shmid, shmdet, fd[2], wCnt, rCnt;
    char *shmadd;
    char rBuf[20];
    shmid = shmget((key_t)55, 2048, 777);
    if (shmid < 0)
    {
        perror("Shmget error ! n");
        exit(0);
    }
    else
    {
        printf("Shmget Success , %d !n", shmid);
    }
    // shmctl()
    // 映射共享内存
    shmadd = shmat(shmid, 0, 0);
    // 成功返回的是一个地址
    if (shmadd < (char *)0)
    {
        perror("Shmadd error ! n ");
        exit(0);
    }
    else
    {
        printf("Shmat Success , %x !n", shmadd);
        while (1)
        {
            printf("input:");
            gets(rBuf);
            fflush(stdin);
            memcpy(shmadd, rBuf, sizeof(rBuf));
            if(!strcmp(shmadd,"end"))
            {
                break;
            }
        }
    }
    shmdet = shmdt(shmadd);
    if (shmdet < 0)
    {
        perror("Shmdet Error ! n ");
        exit(0);
    }
    else
    {
        printf("Shmdet Success %d !n", shmdet);
    }
}
//r.c
// 创建共享内存
// 映射共享内存
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    // 创建共享内存
    int shmid, shmdet, shmcle, wCnt, rCnt;
    char *shmadd;
    char rBuf[20];
    shmid = shmget((key_t)55, 2048, 777);
    if (shmid < 0)
    {
        perror("Shmget error ! n");
        exit(0);
    }
    else
    {
        printf("Shmget Success , %d !n", shmid);
    }
    // shmctl()
    // 映射共享内存
    shmadd = shmat(shmid, 0, 0);
    // 成功返回的是一个地址
    if (shmadd < (char *)0)
    {
        perror("Shmadd error ! n ");
        exit(0);
    }
    else
    {
        while (1)
        {
            printf("Shmat Success , %s !n", shmadd);
            if (!strcmp(shmadd, "end"))
            {
                break;
            }
        }
    }
    shmdet = shmdt(shmadd);
    if (shmdet < 0)
    {
        perror("Shmdet Error ! n ");
        exit(0);
    }
    else
    {
        printf("Shmdet Success %d !n", shmdet);
    }
    shmcle = shmctl(shmid, IPC_RMID, 0);
    if (shmcle < 0)
    {
        perror("Shmctl Error !n");
        exit(0);
    }
    else
    {
        printf("Shmctl Success %d !n", shmcle);
    }
}
消息队列

消息队列具有有名管道的一定特性,但是它可以实现消息的随机查询,比有名管道具有更大的优势

函数目录 pipe

mkfifo

errno

sig(信号)

kill

raise

alarm

pause

signal

shmget

shmat

shmdt

shmctl

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

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

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