Linux的进程间的通信

#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;
}

效果图

1, 和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;
}

1, 读取数据
/*************************************************************************
> 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;
}

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

写数据的

#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;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值