Linux进程间通信demo.c

6 篇文章 0 订阅

1.错误处理函数:

#include<stdio.h>
#include<errno.h>
#include<string.h>

int main(void)
{
    FILE *Fr = fopen("./2.txt", "r");
    //全局变量errno会实时更新,装载的是最新被调用的系统回调的操作状态
    //如下面操作,如果2.txt打开成功,errno装载的值表示的是success,否则其
    //装载的值表示的是failed
    if(NULL == Fr)
    {
        printf("1.errno:%d\n",errno);
        printf("1.errno:%s\n",strerror(errno));
        perror("1.fopen error");
    }
    else
    {
        printf("2.errno:%d\n",errno);
        printf("2.errno:%s\n",strerror(errno));
        perror("2.fopen error");
    }
    return 0;
}

2.进程的创建:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

int main(void)
{
    int i = 0;
    pid_t pid = -1;
    int ret = -1;
    //连续创建3个子进程
    for(i=0; i<3; i++)
    {
        pid = fork();
        if(-1 == pid)
        {
            perror("fork");
            break;
        }
        //fork成功,子进程中返回0;父进程中返回子进程ID
        if(0 == pid)
        {
            break;
        }
    }

    if(0 == i)
    {
        printf("第1个子进程 getpid:%d\n", getpid());
    }
    else if(1 == i)
    {
        printf("第2个子进程 getpid:%d\n", getpid());
    }
    else if(2 == i)
    {
        printf("第3个子进程 getpid:%d\n", getpid());
    }
    else
    {
        //父进程  阻塞 等全部子进程结束,将回收其资源并结束阻塞
        while(-1 != (ret = waitpid(-1, NULL, 0)))
        {
            printf("父进程等待子进程pid:%d\n", ret);
        }
    }

    return 0;
}

3.无名管道

(1)无名管道用于父子进程或者兄弟进程间通信;

(2)系统中使用ulimit -a;命令可以查看管道对应的缓冲区大小;

使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
(1)如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
(2)如果有指向管道写端的文件描述符没关闭(管道写端引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
(3)如果所有指向管道读端的文件描述符都关闭了(管道读端引用计数为0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。当然也可以对SIGPIPE信号实施捕捉,不终止进程。具体方法信号章节详细介绍。
(4)如果有指向管道读端的文件描述符没关闭(管道读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。

总结:
读管道:    
管道中有数据,read返回实际读到的字节数。
管道中无数据:
管道写端被全部关闭,read返回0 (相当于读到文件结尾)
写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu)

写管道:
管道读端全部被关闭, 进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)
管道读端没有全部关闭: 
管道已满,write阻塞。
管道未满,write将数据写入,并返回实际写入的字节数。

3-1.无名管道的创建:

#include<stdio.h>
#include<unistd.h>
int main(void)
{
    int ret = -1;
    int fd[2] = {0};

    //创建一个无名管道,fd[0]用于读,fd[1]用于写
    ret = pipe(fd);
    if(-1 == ret)
    {
        perror("pipe");
        goto err0;
    }

    //返回两个最小的待使用文件描述符供使用
    printf("fd[0]: %d  fd[1]: %d\n", fd[0], fd[1]);

    //关闭文件描述符
    close(fd[0]);
    close(fd[1]);

    return 0;
err0:
    return 1;
    return 0;
}

3-2.无名管道的使用初探:

子进程写,父进程读。

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>

#define SIZE 128

//父子进程间使用无名管道通讯
int main(void)
{
    int ret = -1;
    int fd[2] = {0};
    char buf[SIZE] = {0};
    pid_t pid = -1;

    //创建一个无名管道,fd[0]用于读,fd[1]用于写
    ret = pipe(fd);
    if(-1 == ret)
    {
        perror("pipe");
        goto err0;
    }

    //创建子进程
    pid = fork();
    if(-1 == pid)
    {
        perror("fork");
        goto err0;
    }

    //子进程 写管道
    if(0 == pid)
    {
        memset(buf, 0, SIZE);
        strcpy(buf, "hello man");
        close(fd[0]);//关闭读端

        ret = write(fd[1], buf, strlen(buf));
        if(-1 == ret)
        {
            perror("write");
            close(fd[1]);
            exit(1);
        }
        printf("子进程写管道字节数 ret = %d\n", ret);
        close(fd[1]);
        exit(0);
    }

    //父进程 读管道
    close(fd[1]);//关闭写端
    //wait(NULL);//等待子进程退出
    memset(buf, 0, SIZE);
    ret = read(fd[0], buf, SIZE);//子进程写端未关闭而管道内又无内容时,这里会阻塞等待有内容时再读取
    if(-1 == ret)
    {
        perror("read");
        goto err1;
    }
    printf("从管道中读取的数据:%s\n", buf);
    close(fd[0]);

    return 0;
err1:
    close(fd[0]);
    close(fd[1]);
err0:
    return 1;
}

3-3 无名管道的使用

子进程循环写,父进程只读一次。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define SIZE 128

//父子进程使用无名管道通讯
int main(void)
{
    int ret = -1;
    int status = -1;
    int fd[2] = {0};

    char buf[SIZE];

    pid_t pid = -1;

    //创建一个无名管道
    //fd[0]: 读
    //fd[1]: 写
    ret = pipe(fd);
    if (-1 == ret)
    {
        perror("pipe"); 
        goto err0;
    }

    //创建子进程
    pid = fork();
    if (-1 == pid)
    {
        perror("fork"); 
        goto err1;
    }

    //子进程 不停地写管道
    if (0 == pid)
    {
        //关闭读端
        close(fd[0]);

        printf("hello world child process\n");

        while(1)
        {
            //sleep(1);
            memset(buf, 0, SIZE); 
            strcpy(buf, "hello blackview");

            printf("hello child process while\n");
            //写管道 
            //1. 如果管道被写满了 那么写管道就会阻塞
            //2. 如果管道的读端全部被关闭,那么写管道直接被signal杀死
            ret = write(fd[1], buf, strlen(buf));
            if (ret <= 0)
            {
                perror("write"); 
                break;
            }
            printf("子进程写管道字节数 ret = %d\n", ret); 
        }

        printf("子进程退出...\n");
        close(fd[1]);
        exit(0); 
    }


    //父进程 读管道
    //关闭写端
    close(fd[1]);
    //关闭读端
    close(fd[0]);

    //等待子进程退出
    wait(&status);
    if (WIFSIGNALED(status))
    {
        printf("child proces is killed by signal:%d\n",  WTERMSIG(status)); 
    }

#if 0
    memset(buf, 0, SIZE);
    //从管道中读取数据 管道默认是阻塞
    ret = read(fd[0], buf, SIZE);
    if (-1 == ret)
    {
        perror("read"); 
        goto err1;
    }

    printf("从管道中读取的数据: %s\n", buf);

    close(fd[0]);
#endif
    return 0;
err1:
    close(fd[0]);
    close(fd[1]);
err0:
    return 1;
}

3-4.无名管道的使用

 验证:

1.如果管道中没有数据,那么读管道进程默认会阻塞;

2.如果写端被全部关闭,那么读管道的进程读管道函数会结束阻塞并返回0。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#define SIZE 128

//父子进程使用无名管道通讯
int main(void)
{
    int ret = -1;
    int status = -1;
    int fd[2] = {0};

    char buf[SIZE];

    pid_t pid = -1;

    //创建一个无名管道
    //fd[0]: 读
    //fd[1]: 写
    ret = pipe(fd);
    if (-1 == ret)
    {
        perror("pipe"); 
        goto err0;
    }

    //创建子进程
    pid = fork();
    if (-1 == pid)
    {
        perror("fork"); 
        goto err1;
    }

    //子进程 不停地写管道
    if (0 == pid)
    {
        //关闭读端
        close(fd[0]);

#if 0 //验证;管道无内容,读端默认阻塞
        printf("hello world child process\n");

        //睡眠10秒
        sleep(10);

        //sleep(1);
        memset(buf, 0, SIZE);
        strcpy(buf, "hello blackview");

        ret = write(fd[1], buf, strlen(buf));
        if (ret <= 0)
        {
            perror("write");
        }
        printf("子进程写管道字节数 ret = %d\n", ret);

        printf("子进程退出...\n");
#endif
        close(fd[1]);
        exit(0);
    }


    //父进程 读管道
    //关闭写端
    close(fd[1]);

#if 0
    //等待子进程退出
    wait(&status);
    if (WIFSIGNALED(status))
    {
        printf("child proces is killed by signal:%d\n",  WTERMSIG(status));
    }
#endif

    memset(buf, 0, SIZE);
    //从管道中读取数据 管道默认是阻塞
    //1. 如果管道中没有数据,那么读管道进程会阻塞
    //2. 如果写端全部关闭,那么读管道的进程读管道返回0
    ret = read(fd[0], buf, SIZE);
    printf("ret:%d\n", ret);
    if (-1 == ret)
    {
        perror("read");
        goto err1;
    }

    printf("从管道中读取的数据: %s\n", buf);

    close(fd[0]);

    return 0;
err1:
    close(fd[0]);
    close(fd[1]);
err0:
    return 1;
}

3-5 无名管道的使用

 读端非阻塞属性的使用(管道无内容,读端不等待,直接返回-1)。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define SIZE 128

//父子进程使用无名管道通讯
int main(void)
{
    int ret = -1;
    int status = -1;
    int arg = -1;
    int fd[2] = {0};

    char buf[SIZE];

    pid_t pid = -1;

    //创建一个无名管道
    //fd[0]: 读
    //fd[1]: 写
    ret = pipe(fd);
    if (-1 == ret)
    {
        perror("pipe"); 
        goto err0;
    }

    //创建子进程
    pid = fork();
    if (-1 == pid)
    {
        perror("fork"); 
        goto err1;
    }

    //子进程 不停地写管道
    if (0 == pid)
    {
        //关闭读端
        close(fd[0]);

#if 0
        printf("hello world child process\n");

        //睡眠10秒
        sleep(10);

        //sleep(1);
        memset(buf, 0, SIZE); 
        strcpy(buf, "hello blackview");

        ret = write(fd[1], buf, strlen(buf));
        if (ret <= 0)
        {
            perror("write"); 
        }
        printf("子进程写管道字节数 ret = %d\n", ret); 

        printf("子进程退出...\n");
#endif
        sleep(10);

        close(fd[1]);
        exit(0); 
    }


    //父进程 读管道
    //关闭写端
    close(fd[1]);

#if 0
    //等待子进程退出
    wait(&status);
    if (WIFSIGNALED(status))
    {
        printf("child proces is killed by signal:%d\n",  WTERMSIG(status)); 
    }
#endif

    //获取文件描述符属性
    arg = fcntl(fd[0], F_GETFL); 
    //设置非阻塞
    arg = arg | O_NONBLOCK;
    //设置文件描述符属性
    fcntl(fd[0], F_SETFL, arg);

    memset(buf, 0, SIZE);
    //从管道中读取数据 管道默认是阻塞
    //1. 如果写端没有关闭, 读端设置为非阻塞,如果没有数据读, 那么就直接返回-1
    ret = read(fd[0], buf, SIZE);
    printf("ret:%d\n", ret);
    if (-1 == ret)
    {
        perror("read"); 
        goto err1;
    }

    printf("从管道中读取的数据: %s\n", buf);

    close(fd[0]);

    return 0;
err1:
    close(fd[0]);
    close(fd[1]);
err0:
    return 1;
}

3-6无名管道的使用

写端非阻塞属性的使用(管道已满写端不阻塞等待,直接返回)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define SIZE 128

//父子进程使用无名管道通讯
int main(void)
{
    int ret = -1;
    int status = -1;
    int arg = -1;
    int fd[2] = {0};

    char buf[SIZE];

    pid_t pid = -1;

    //创建一个无名管道
    //fd[0]: 读
    //fd[1]: 写
    ret = pipe(fd);
    if (-1 == ret)
    {
        perror("pipe"); 
        goto err0;
    }

    //创建子进程
    pid = fork();
    if (-1 == pid)
    {
        perror("fork"); 
        goto err1;
    }

    //子进程 不停地写管道
    if (0 == pid)
    {
        //关闭读端
        close(fd[0]);

        printf("hello world child process\n");

        //获取文件描述符属性
        arg = fcntl(fd[1], F_GETFL); 
        //设置非阻塞
        arg = arg | O_NONBLOCK;
        //设置文件描述符属性
        fcntl(fd[1], F_SETFL, arg);

        while(1)
        {
            //sleep(1);
            memset(buf, 0, SIZE); 
            strcpy(buf, "hello blackview");

            ret = write(fd[1], buf, strlen(buf));
            if (ret <= 0)
            {
                perror("write"); 
                break;
            }
            printf("子进程写管道字节数 ret = %d\n", ret); 
        }

        printf("子进程退出...\n");

        close(fd[1]);
        exit(0); 
    }


    //父进程 读管道
    //关闭写端
    close(fd[1]);

    //等待子进程退出
    wait(&status);
    if (WIFSIGNALED(status))
    {
        printf("child proces is killed by signal:%d\n",  WTERMSIG(status)); 
    }

    memset(buf, 0, SIZE);
    //从管道中读取数据 管道默认是阻塞
    //1. 如果写端没有关闭, 读端设置为非阻塞,如果没有数据读, 那么就直接返回-1
    ret = read(fd[0], buf, SIZE);
    printf("ret:%d\n", ret);
    if (-1 == ret)
    {
        perror("read"); 
        goto err1;
    }

    printf("从管道中读取的数据: %s\n", buf);

    close(fd[0]);

    return 0;
err1:
    close(fd[0]);
    close(fd[1]);
err0:
    return 1;
}

3-7 无名管道的使用

 查看读、写端缓冲区大小。

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

int main(void)
{
    int ret = -1;
    int fd[2] = {0};

    //创建无名管道
    ret = pipe(fd);
    if (-1 == ret)
    {
        perror("pipe"); 
        goto err0;
    }

    //输出管道缓冲区
    printf("_PC_PIPE_BUF: %ld\n", fpathconf(fd[0], _PC_PIPE_BUF));
    printf("_PC_PIPE_BUF: %ld\n", fpathconf(fd[1], _PC_PIPE_BUF));

    close(fd[0]);
    close(fd[1]);

    return 0;
err0:
    return 1;
}

4.有名管道

命名管道(FIFO)和无名管道(pipe)有一些特点是相同的,不一样的地方在于:
(1)FIFO 在文件系统中作为一个特殊的文件而存在,但 pipe 中的内容却存放在内存中。
(2)当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。
(3)FIFO 有名字,不相关的进程可以通过打开命名管道进行通信。 

4-1.有名管道的创建:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>

//创建一个有名管道
int main(void)
{
    int ret = -1;

    ret = mkfifo("./my_fifo", 0644);//有名管道的名字和权限
    if(-1 == ret)
    {
        perror("mkfifo");
        goto err0;
    }
    puts("mkfifo ok...");
    
    return 0;
err0:
    return 1;
}

4-2.有名管道的使用1

 一个进程写,一个进程读。

write.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE (128)

int main(void)
{
	int ret = 0;
	int fd = -1;
	char buf[SIZE] = {0};
	
	if(0 != access("./myfifo", F_OK))//管道不存在则创建它
	{
		ret = mkfifo("./myfifo", 0777);
		if(0 != ret)
		{
			perror("mkfifo");
			goto err0;
		}
	}
	
	fd = open("./myfifo", O_WRONLY);
	if(-1 == fd)
	{
		perror("open myfifo as write-only");
		goto err0;
	}
	
	sprintf(buf, "%s", "Nothing is impossible for a willing heart!");
	ret = -1;
	ret = write(fd, buf, strlen(buf));//写完后默认是会阻塞的,等待管道内容被读取之后才继续往下执行
	if(-1 == ret)
	{
		perror("write to myfifo");
		goto err1;
	}
	printf("write data length is [%d] ?= [%lu]\n", ret, strlen(buf));
	
	close(fd);
	
	return 0;
err1:
    close(fd);
err0:
	return 1;
}

read.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE (128)

int main(void)
{
	int ret = 0;
	int fd = -1;
	char buf[SIZE] = {0};
	
	if(0 != access("./myfifo", F_OK))//管道不存在则创建它
	{
		ret = mkfifo("./myfifo", 0777);
		if(0 != ret)
		{
			perror("mkfifo");
			goto err0;
		}
	}
	
	fd = open("./myfifo", O_RDONLY);
	if(-1 == fd)
	{
		perror("open myfifo as read-only");
		goto err0;
	}
	
	ret = -1;
	ret = read(fd, buf, SIZE);//如果管道中无内容,默认是阻塞等待读取的
	if(-1 == ret)
	{
		perror("read data from myfifo");
		goto err1;
	}
	
	printf("buf[%s], length[%d]\n", buf, ret);
	
	close(fd);
	return 0;
err1:
    close(fd);
err0:
    return 1;
}

4-3.有名管道的使用2

 一个进程循环写入,一个进程循环读取。

write.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE (128)

int main(void)
{
	int ret = 0;
	int fd = -1;
	char buf[SIZE] = {0};
	int cnt = 0;
	
	if(0 != access("./myfifo", F_OK))
	{
		ret = mkfifo("./myfifo", 0644);
		if(0 != ret)
		{
			perror("mkfifo");
			goto err0;
		}
	}
	
	fd = open("./myfifo", O_WRONLY);
	if(-1 == fd)
	{
		perror("open myfifo as write-only");
		goto err0;
	}
	
	while(1)//循环向管道写入数据
	{
		memset(buf, 0, SIZE);
		sprintf(buf, "%d %s", cnt++, "Nothing is impossible for a willing heart!");
		
		ret = -1;
		ret = write(fd, buf, strlen(buf));
		if(-1 == ret)
		{
			perror("write data to myfifo");
			close(fd);
			return 1;
		}
		printf("write data length is [%d] ?= [%lu]\n", ret, strlen(buf));
		sleep(1);
	}
	
	return 0;
err0:
    return 1;
}

read.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE (128)

int main(void)
{
	int ret = 0;
	int fd = -1;
	char buf[SIZE] = {0};

    if(0 != access("./myfifo", F_OK))
	{
		ret = mkfifo("./myfifo", 0644);
		if(-1 == fd)
		{
			perror("mkfifo");
			goto err0;
		}
	}
	
	fd = open("./myfifo", O_RDONLY);
	if(-1 == fd)
	{
		perror("open myfifo as read-only");
		goto err0;
	}
	
	while(1)//循环读取管道中的数据
	{
		memset(buf, 0, SIZE);
		ret = -1;
		ret = read(fd, buf, SIZE);
		if(-1 == ret)
		{
			perror("read data from myfifo");
			close(fd);
			return 1;
		}
		puts(buf);
	}
	
	return 0;
err0:
    return 1;
}

4-4.有名管道的使用3

两个进程A和B聊天。 

A.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE (128)

int main(void)
{
	int ret = 0;
	int fd = -1;
	int fd2 = -1;
    char buf[SIZE] = {0};
	
	if(0 != access("./fifo_A", F_OK))
	{
		ret = mkfifo("./fifo_A", 0644);
		if(0 != ret)
		{
			perror("create fifo_A");
			goto err0;
		}
	}
	
	if(0 != access("./fifo_B", F_OK))
	{
		ret = mkfifo("./fifo_B", 0644);
		if(0 != ret)
		{
			perror("create fifo_B");
			goto err0;
		}
	}
	
	fd = open("./fifo_A", O_WRONLY);//此处会默认阻塞等待别处以只读方式打开(如果这里先只写打开的话),再继续往下执行
	if(-1 == fd)
	{
		perror("open fifo_A as write-only");
		goto err0;
	}
	
	fd2 = open("./fifo_B", O_RDONLY);//同理
	if(-1 == fd2)
	{
		perror("open fifo_B as read-only");
		goto err1;
	}
	
	puts("ok, Let's talk:");
	//printf("ok, Let's talk:\n");
	//return 1;
	
	while(1)//先写再读
	{
		memset(buf, 0, SIZE);
		if(NULL == fgets(buf, SIZE, stdin))
		{
			perror("get datas from terminal");
		}
		else
		{
			ret = write(fd, buf, strlen(buf));
			if(-1 == ret)
			{
				perror("write data to fifo_A");
			}
		}
		
		memset(buf, 0, SIZE);
		ret = read(fd2, buf, SIZE);
		if(-1 == ret)
		{
			perror("read data from fifo_B");
		}
		else
		{
			puts(buf);
		}
	}
	close(fd);
	close(fd2);
	return 0;
err1:
    close(fd);
err0:
    return 1;
}

B.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>

#define SIZE (128)

int main(void)
{
	int ret = 0;
	int fd = -1;
	int fd2 = -1;
    char buf[SIZE] = {0};
	
	if(0 != access("./fifo_A", F_OK))
	{
		ret = mkfifo("./fifo_A", 0644);
		if(0 != ret)
		{
			perror("create fifo_A");
			goto err0;
		}
	}
	
	if(0 != access("./fifo_B", F_OK))
	{
		ret = mkfifo("./fifo_B", 0644);
		if(0 != ret)
		{
			perror("create fifo_B");
			goto err0;
		}
	}
	
	fd = open("./fifo_A", O_RDONLY);//此处会默认阻塞等待别处以只写方式打开(如果这里先只读打开的话),再继续往下执行
	if(-1 == fd)
	{
		perror("open fifo_A as write-only");
		goto err0;
	}
	
	fd2 = open("./fifo_B", O_WRONLY);//同理
	if(-1 == fd2)
	{
		perror("open fifo_B as read-only");
		goto err1;
	}
	
	puts("ok, Let's talk:");
	
	while(1)//先读再写
	{
		memset(buf, 0, SIZE);
		ret = read(fd, buf, SIZE);
		if(-1 == ret)
		{
			perror("read data from fifo_A");
		}
		else
		{
			puts(buf);
		}
		
		memset(buf, 0, SIZE);
		if(NULL == fgets(buf, SIZE, stdin))
		{
			perror("get datas from terminal");
		}
		else
		{
			ret = write(fd2, buf, strlen(buf));
			if(-1 == ret)
			{
				perror("write data to fifo_B");
			}
		}
	}
	close(fd);
	close(fd2);
	return 0;
err1:
    close(fd);
err0:
    return 1;
}

4-5.有名管道的使用4

两个进程A和B聊天,加入线程防阻塞。

A.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<pthread.h>

#define SIZE (128)

void* writeData(void* arg)
{
	int ret = -1;
	int fd = *(int*)arg;
	char buf[SIZE] = {0};
	
	while(1)
	{
		memset(buf, 0, SIZE);
		if(NULL == fgets(buf, SIZE, stdin))
		{
			perror("get datas from terminal");
		}
		else
		{
			ret = write(fd, buf, strlen(buf));
			if(-1 == ret)
			{
				perror("write data to fifo_A");
			}
		}
		//usleep(200 * 1000);
	}
	
	return NULL;
}

int main(void)
{
	int ret = 0;
	int fd = -1;
	int fd2 = -1;
    char buf[SIZE] = {0};
	pthread_t writeThread;
	
	if(0 != access("./fifo_A", F_OK))
	{
		ret = mkfifo("./fifo_A", 0644);
		if(0 != ret)
		{
			perror("create fifo_A");
			goto err0;
		}
	}
	
	if(0 != access("./fifo_B", F_OK))
	{
		ret = mkfifo("./fifo_B", 0644);
		if(0 != ret)
		{
			perror("create fifo_B");
			goto err0;
		}
	}
	
	fd = open("./fifo_A", O_WRONLY);//此处会默认阻塞等待别处以只读方式打开(如果这里先只写打开的话),再继续往下执行
	if(-1 == fd)
	{
		perror("open fifo_A as write-only");
		goto err0;
	}
	
	fd2 = open("./fifo_B", O_RDONLY);//同理
	if(-1 == fd2)
	{
		perror("open fifo_B as read-only");
		goto err1;
	}
	
	puts("ok, Let's talk:");
	
	ret = pthread_create(&writeThread, NULL, (void*)writeData, (void*)&fd);//创建线程循环向A写入
	if(0 != ret)
	{
		perror("pthread_create");
		goto err2;
	}
	
	while(1)//循环从B读取
	{
		memset(buf, 0, SIZE);
		ret = read(fd2, buf, SIZE);
		if(-1 == ret)
		{
			perror("read data from fifo_B");
		}
		else
		{
			printf("B:%s", buf);
		}
		//usleep(200 * 1000);
	}
	close(fd);
	close(fd2);
	return 0;
err2:
    return ret;
err1:
    close(fd);
err0:
    return 1;
}

B.c

#include<stdio.h>
#include<sys/types.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<pthread.h>
#define SIZE (128)

void* readData(void* arg)
{
	int ret = -1;
	int fd = *(int*)arg;
	char buf[SIZE] = {0};
	
	while(1)
	{
		memset(buf, 0, SIZE);
		ret = read(fd, buf, SIZE);
		if(-1 == ret)
		{
			perror("read data from fifo_A");
		}
		else
		{
			printf("A:%s", buf);
		}
		//usleep(200*1000);
	}
	
	return NULL;
}

int main(void)
{
	int ret = 0;
	int fd = -1;
	int fd2 = -1;
    char buf[SIZE] = {0};
	pthread_t readThread;
	
	if(0 != access("./fifo_A", F_OK))
	{
		ret = mkfifo("./fifo_A", 0644);
		if(0 != ret)
		{
			perror("create fifo_A");
			goto err0;
		}
	}
	
	if(0 != access("./fifo_B", F_OK))
	{
		ret = mkfifo("./fifo_B", 0644);
		if(0 != ret)
		{
			perror("create fifo_B");
			goto err0;
		}
	}
	
	fd = open("./fifo_A", O_RDONLY);//此处会默认阻塞等待别处以只写方式打开(如果这里先只读打开的话),再继续往下执行
	if(-1 == fd)
	{
		perror("open fifo_A as write-only");
		goto err0;
	}
	
	fd2 = open("./fifo_B", O_WRONLY);//同理
	if(-1 == fd2)
	{
		perror("open fifo_B as read-only");
		goto err1;
	}
	
	puts("ok, Let's talk:");
	
	ret = pthread_create(&readThread, NULL, (void*)readData, (void*)&fd);//创建线程循环从A读取
	if(0 != ret)
	{
		perror("pthread_create");
		goto err2;
	}
	
	while(1)//循环向B写入
	{
		memset(buf, 0, SIZE);
		if(NULL == fgets(buf, SIZE, stdin))
		{
			perror("get datas from terminal");
		}
		else
		{
			ret = write(fd2, buf, strlen(buf));
			if(-1 == ret)
			{
				perror("write data to fifo_B");
			}
		}
		//usleep(200*1000);
	}
	close(fd);
	close(fd2);
	return 0;
err2:
    return ret;
err1:
    close(fd);
err0:
    return 1;
}

5.内存映射

1.映射函数mmap的使用

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>


int main(void)
{
    int fd = -1;
    int len = 0;

    void *addr = NULL;

    //打开文件
    fd = open("txt", O_RDWR | O_CREAT, 0644);
    //fd = open("txt", O_RDONLY);
    if (-1 == fd){
        perror("open"); 
        goto err0;
    }
    
    //获取文件长度
    len = lseek(fd, 0, SEEK_END);
    if (-1 == len){
        perror("lseek"); 
        goto err1;
    }
    printf("fd:%d len: %d\n", fd, len);

    //映射
    //MAP_PRIVATE : 对映射区的写入操作会产生一个映射区的复制(copy - on - write), 对此区域所做的修改不会写回原文件。
    //addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == addr){
        perror("mmap"); 
        goto err1;
    }

    //addr++;
    printf("映射ok....\n");
    
    //关闭文件
    close(fd);

    strcpy(addr, "hello itcast"); 

    printf("%s\n", (char*)(addr + 1));

    //解除映射
    munmap(addr, len);

    return 0;
err1:
    close(fd);
err0:
    return 1;
}

2.用于父子进程通信

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>


int main(void)
{
    int fd = -1;
    int len = 0;

    pid_t pid = -1;

    void *addr = NULL;

    //打开文件
    fd = open("txt", O_RDWR | O_CREAT, 0644);
    //fd = open("txt", O_RDONLY);
    if (-1 == fd)
    {
        perror("open"); 
        goto err0;
    }
    
    //获取文件长度
    len = lseek(fd, 0, SEEK_END);
    if (-1 == len)
    {
        perror("lseek"); 
        goto err1;
    }
    printf("fd:%d len: %d\n", fd, len);

    //映射
    //MAP_PRIVATE : 对映射区的写入操作会产生一个映射区的复制(copy - on - write), 对此区域所做的修改不会写回原文件。
    //addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == addr)
    {
        perror("mmap"); 
        goto err1;
    }

    //addr++;
    printf("映射ok....\n");
    //关闭文件
    close(fd);


    //创建一个子进程
    pid = fork();
    if (-1 == pid)
    {
        perror("fork"); 
        goto err0;
    }

    //子进程
    if (0 == pid)
    {
        //写映射区
        strcpy(addr, "hello itcast"); 
        printf("子进程退出....\n");

        //解除映射
        munmap(addr, len);

        exit(0);
    }

    //等待子进程退出
    wait(NULL);

    //父进程
    printf("%s\n", (char*)addr);

    //解除映射
    munmap(addr, len);

    return 0;
err1:
    close(fd);
err0:
    return 1;
}

3.普通进程间通信

3.1 read.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>


int main(void)
{
    int fd = -1;
    int len = 0;

    void *addr = NULL;

    //打开文件
    fd = open("txt", O_RDWR | O_CREAT, 0644);
    if (-1 == fd)
    {
        perror("open"); 
        goto err0;
    }
    
    //获取文件长度
    len = lseek(fd, 0, SEEK_END);
    if (-1 == len)
    {
        perror("lseek"); 
        goto err1;
    }
    printf("fd:%d len: %d\n", fd, len);

    //映射
    //MAP_PRIVATE : 对映射区的写入操作会产生一个映射区的复制(copy - on - write), 对此区域所做的修改不会写回原文件。
    //addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == addr)
    {
        perror("mmap"); 
        goto err1;
    }

    //addr++;
    printf("映射ok....\n");
    
    //关闭文件
    close(fd);

    printf("addr: %s\n", (char*)addr);

    //解除映射
    munmap(addr, len);

    return 0;
err1:
    close(fd);
err0:
    return 1;
}

3.2 write.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>


int main(void)
{
    int fd = -1;
    int len = 0;

    void *addr = NULL;

    //打开文件
    fd = open("txt", O_RDWR | O_CREAT, 0644);
    //fd = open("txt", O_RDONLY);
    if (-1 == fd)
    {
        perror("open"); 
        goto err0;
    }
    
    //获取文件长度
    len = lseek(fd, 0, SEEK_END);
    if (-1 == len)
    {
        perror("lseek"); 
        goto err1;
    }
    printf("fd:%d len: %d\n", fd, len);

    //映射
    //MAP_PRIVATE : 对映射区的写入操作会产生一个映射区的复制(copy - on - write), 对此区域所做的修改不会写回原文件。
    //addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (MAP_FAILED == addr)
    {
        perror("mmap"); 
        goto err1;
    }

    //addr++;
    printf("映射ok....\n");
    
    //关闭文件
    close(fd);

    strcpy(addr, "hello itcast"); 


    //解除映射
    munmap(addr, len);

    return 0;
err1:
    close(fd);
err0:
    return 1;
}

4.匿名映射

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>


int main(void)
{
    int len = 0;

    pid_t pid = -1;

    void *addr = NULL;

    len = 1024;

    //创建一个匿名映射
    addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    if (MAP_FAILED == addr)
    {
        perror("mmap"); 
        goto err1;
    }

    //addr++;
    printf("创建匿名映射ok....\n");


    //创建一个子进程
    pid = fork();
    if (-1 == pid)
    {
        perror("fork"); 
        goto err0;
    }

    //子进程
    if (0 == pid)
    {
        //写映射区
        strcpy(addr, "hello itcast"); 
        printf("子进程退出....\n");

        //解除映射
        munmap(addr, len);

        exit(0);
    }

    //等待子进程退出
    wait(NULL);

    //父进程
    printf("%s\n", (char*)addr);

    //解除映射
    munmap(addr, len);

    return 0;
err1:
err0:
    return 1;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值