Linux的进程间的通信

来源:互联网 发布:淘宝卖cf神器是真的吗 编辑:程序博客网 时间:2024/04/27 20:51

这里写图片描述

#define  STDIN_FILENO           0#define  STDOUT_FILENO          1#define  STDERR_FILENO          2

一,管道进程的pipe函数和dup2函数组合使用父子进程间通信

参数是数组管道文件描述符

pipe参数是:

  1. fd[0]是读文件描述符,
  2. fd[2]是写文件描述符
 int pipe(int pipefd[2]);

这里写图片描述
案例1:

/*************************************************************************    > File Name: pipe.c    > Author: songli    > QQ: 2734030745    > Mail: 15850774503@163.com    > CSDN: http://my.csdn.net/Poisx    > github: https://github.com/chensongpoixs    > Created Time: Fri 20 Oct 2017 10:22:29 PM CST ************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <fcntl.h>int main(int argc, char *argv[]){    //管道数组文件描述符    int fd[2];           int ret;    int i, n = 2;    //创建管道    ret = pipe(fd);    //文件描述符    pid_t pid;    if (ret < 0)    {        perror("pipe error");        return -1;    }    for (i = 0; i < n; i++)    {        //创建子进程        pid = fork();        if (pid < 0) // 异常处理        {            perror("fork error");            return -1;        }        else if (pid > 0) // 父进程的操作        {            printf("father fpid:%d, cpid:%d\n", getpid(), pid);        }        else if (pid == 0) //子进程的操作        {            printf("child fpid:%d, cpid:%d\n", getppid(), getpid());            break; //防止子线程创建子进程        }    }    //===============  子进程的操作=============================    if (i == 0)    {        printf("no child n = %d, cpid:%d\n", i, getpid());        //=================写入数据 =====================        close(fd[0]); //关闭读取文件描述符        //标准输入也是 文件描述符   中的1        dup2(fd[1], STDOUT_FILENO);        // 执行  写入命令        execlp("ps", "ps", "-ef", NULL);        close(fd[1]); //关闭写入文件描述符        return 0; //signal  正常退出    }    if (i == 1)    {        printf("no child n = %d, cpid:%d\n", i, getpid());        //=================写入数据 =====================        close(fd[1]); //关闭 写描述符文件描述符        //标准输出也是 文件描述符   中的1        dup2(fd[0], STDIN_FILENO);        // 执行  写入命令        execlp("grep", "grep", "--color", "bash", NULL);        close(fd[0]); //关闭写入文件描述符        return 0; //signal  正常退出    }    //=================      主进程的操作 ========================    if (i == n)    {        //pcb 进程块pid        pid_t wpid;        int status;        while (1)        {            //等待线程            wpid = waitpid(-1, &status, WNOHANG );            if (wpid == 0) //有子进程程的操作            {                sleep(1);                continue;            }            else if (wpid == -1) // 没有子进程的操作            {                printf("退出子进程的wpid:%d\n", wpid);                exit(0);            }            else if (wpid > 0)  //什么原因退出            {                if (WIFEXITED(status)) //正常退出                {                    printf("子进程wpid:%d, status:%d\n", wpid, WEXITSTATUS(status));                }                if (WIFSIGNALED(status))                {                    printf("子进程wpid:%d, status:%d\n", wpid, WTERMSIG(status));                }            }        }    }    return 0;}

效果图
这里写图片描述

和fcntl函数一起使用可以数组read函数非阻塞

/*************************************************************************    > File Name: pipe_fcntl.c    > Author: songli    > QQ: 2734030745    > Mail: 15850774503@163.com    > CSDN: http://my.csdn.net/Poisx    > github: https://github.com/chensongpoixs    > Created Time: Fri 20 Oct 2017 10:47:08 PM CST ************************************************************************/#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <string.h>int main(int argc, char *argv[]){    //数组文件描述符    int fd[2];    int ret;    char buf[1024];    //创建管道    ret = pipe(fd);    if (ret < 0)    {        perror("pipe error");        return -1;    }    //pcb进程控制块pid    pid_t pid;    //创建子线程    pid = fork();    if (pid < 0) //异常处理    {        perror("fork error");        return -1;    }    else if (pid > 0) //父进程的处理    {        printf("father fpid:%d, cpid:%d\n", getpid(), pid);        //==============读取数据==================        close(fd[1]); //关闭写文件操作        //==================    在同一个进程中使用非阻塞使用fcntl函数 =========================================        int flags = fcntl(fd[0], F_GETFL );        flags |= O_NONBLOCK;        fcntl(fd[0], F_SETFL, flags);        //=============================================================        while(1)        {            sleep(1);            memset(buf, 0x00, sizeof(buf));            ret = read(fd[0], buf, sizeof(buf));            printf("读取数据的大小:%d buf = %s\n", ret, buf);        }        close(fd[0]);    }    else if (pid == 0) //子进程的操作    {       printf("child fpid:%d, cpid:%d\n", getppid(), getpid());       //========== 写操作===================         close(fd[0]); //关闭读取文件描述符        int i = 0;        while (1)        {            sleep(1);            memset(buf, 0x00, sizeof(buf));            sprintf(buf, "[%d]:[%s]", i++, "陈丽, 杨艳");            write(fd[1], buf, strlen(buf));        }        close(fd[1]);    }    return 0;}

* 效果图*

二,管道 mkfifio函数的使用

这里写图片描述
mkfifo命令生成管道文件
这里写图片描述

mkfifo函数 第一参数路径, 第二是权限

 int mkfifo(const char *pathname, mode_t mode);

写入数据

/*************************************************************************    > File Name: fifo_write.c    > Author: songli    > QQ: 2734030745    > Mail: 15850774503@163.com    > CSDN: http://my.csdn.net/Poisx    > github: https://github.com/chensongpoixs    > Created Time: Fri 20 Oct 2017 11:22:50 PM CST ************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/wait.h>int main(int argc, char *argv[]){    // 文件描述符    int fd;    int ret;    //判断是否创建管道文件    if ((ret = access("./myfifo", F_OK)) == -1)    {        //创建管道        ret =  mkfifo("./myfifo", 0777);        if (ret < 0)        {            perror("mkfifo error");            return -1;        }    }    //打开文件    fd = open("./myfifo", O_RDWR);    if (fd < 0)    {        perror("open error");        return -1;    }    //=====================写数据到管道中============================    while (1)    {        sleep(1);        write(fd, "陈丽, 杨艳", strlen("杨艳"));    }    close(fd);    return 0;}

读取数据

/*************************************************************************> File Name: fifo_read.c> Author: songli> QQ: 2734030745> Mail: 15850774503@163.com> CSDN: http://my.csdn.net/Poisx> github: https://github.com/chensongpoixs> Created Time: Fri 20 Oct 2017 11:31:07 PM CST************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/types.h>int main(int argc, char *argv[]){    //文件描述符    int fd;    int ret;    char buf[1024];    //检测是否有管道文件    if ((ret = access("./myfifo", F_OK)) == -1)    {        ret = mkfifo("./myfifo", 0777);        if (ret < 0)        {            perror("mkfifo error");            return -1;        }    }    //打开管道文件    fd = open("./myfifo", O_RDWR);    if (fd < 0)    {        perror("open error");        return -1;    }    //==============读取管道中数据=========================    while (1)    {        //=================   设置read函数非阻塞  ==================/*        int flags = fcntl(fd, F_GETFL);        flags |= O_NONBLOCK;        fcntl(fd, F_SETFL, flags);*/        sleep(1);        memset(buf, 0x00, sizeof(buf));        ret = read(fd, buf, sizeof(buf));        printf("读取数据:%d, buf = %s\n", ret, buf);    }    //关闭文件    close(fd);    return 0;}

效果图
这里写图片描述

三,mmap内存映射的机制

每个应用程序有虚的4个G的内存 由MMU把实际 要用的映射到内存中就是内核

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <sys/mman.h>int main(int argc, char *argv[]){    //文件描述符    int fd;    int len;    fd = open("./text.log", O_RDWR);    if (fd < 0)    {        perror("open error");        return -1;    }    //文件大小    len = lseek(fd, 0, SEEK_END);    //参数一:NULL    //参数二:文件的大小,不能为0    //参数三:权限    //参数四:是否同步的硬盘中    //参数五:文件指针    //参数六:文件开始位置    void *ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);    if (ptr == MAP_FAILED)    {        perror("mmap error");        return -1;    }    char *p = (char*)ptr;    strcpy(p, "陈丽");    //参数一:文件指针    //参数二:文件大小    munmap(ptr, len);    //关闭文件    close(fd);    return 0;}

没有告关系的进程之间通信

写数据的

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/mman.h>#include <sys/types.h>#include <sys/types.h>#include <unistd.h>#include <fcntl.h>int main(int argc, char *argv[]){    //文件描述符    int fd;    int len; //文件大小    int ret; //状态码    //打开文件    fd = open("./text.log", O_RDWR);    if (fd < 0)    {        perror("open error");        return -1;    }    //文件大小    len = lseek(fd, 0, SEEK_END);    //映射到内核中    void * ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);    if (ptr == MAP_FAILED)    {        perror("mmap error");        return -1;    }    char * p = (char *) ptr;    strcpy(p, "陈丽, 王蓉");    //关闭    munmap(ptr, len);    close(fd);    return 0;}

读取数据

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>#include <sys/mman.h>#include <fcntl.h>/**读取数据mmap_read**/int main(int argc, char *argv[]){    //文件指针    int fd;    int len; //文件大小    void * ptr; //映射内存地址    char buf[1024];    //打开文件    fd = open("./text.log", O_RDWR);    if (fd < 0)    {        perror("open error");        return -1;    }    //文件大小    len = lseek(fd, 0, SEEK_END);    //创建映射    ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);    if (ptr == MAP_FAILED)    {        perror("mmap error");        return -1;    }    //=============读取 map内存的数据===================    //while (1)    //{        //memset(buf, 0x00, sizeof(buf));    //  read(fd, buf, sizeof(buf));    char *p = (char *) ptr;        printf("读取数据:%s\n", p);    //}    munmap(ptr, len);    //关闭文件操作    close(fd);    return 0;}

进程间通信的自定义

/* *父子进程交替数数。 */#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <signal.h>#include <error.h>pid_t pid;void sig_handler_p(int sig) //parent 父进程{    static int i = 1;    printf("pid = %d, I'm father\t%d\n", getpid(), i);    sleep(1);    i += 2;    kill(pid, SIGUSR1);     //为避免竞态条件出现,应该在捕捉函数内完成数数及信号发送.}void sig_handler_c(int sig) //child  子进程{    static int i = 2;    printf("pid = %d, I am child\t%d\n", getpid(), i);    sleep(1);    i += 2;    kill(getppid(), SIGUSR2);}int main(void){    struct sigaction newact_p, oldact_p;        //父进程使用    struct sigaction newact_c, oldact_c;        //子进程使用    //子进程响应SIGUSR1    newact_c.sa_handler = sig_handler_c;    sigemptyset(&newact_c.sa_mask);    newact_c.sa_flags = 0;    sigaction(SIGUSR1, &newact_c, &oldact_c);//注册捕捉信号(捕捉的信号,传入参数新的处理方法,传出参数旧的处理方法)    //父进程响应SIGUSR2    newact_p.sa_handler = sig_handler_p;    sigemptyset(&newact_p.sa_mask);    newact_p.sa_flags = 0;    newact_p.sa_flags |= SA_RESTART;//多加这一行可以将被信号打断的系统调用重启。    sigaction(SIGUSR2, &newact_p, &oldact_p);//注册捕捉信号(捕捉的信号,传入参数新的处理方法,传出参数旧的处理方法)    pid = fork();//此时父子进程都注册了2个信号处理函数,但都只会收到其中一个信号,子进程只收SIGUSR1,父进程只收SIGUSR2    if (pid == 0)     {                   //子进程        while (1);    }    else     {                       //父进程        raise(SIGUSR2);//自己给自己发信号2        if (wait(NULL))         {           //wait有可能被信号打断。            perror("wait error");        }        //while (1);                //或者不使用wait使用这条语句也可以实现。    }    return 0;}
原创粉丝点击