Linux-C 进程通信之管道

Linux-C 进程通信之管道

一、简述

        记--对管道的认识与练习。练习进程之间通过管带进行通信。管道包含:有名管道、无名管道(匿名管道)

            无名管道pipe:
                1,没有名字的
                2,半双工
                3,通过直系亲属访问继承(因为没有名字,其他程序无法通过获取文件描述符的方式进行操作此管道)
                4,管道默认会阻塞
                5,不能用lseek定位
                6,操作没有原子性
                                   
                                   
            有名管道fifo:(文件)
                1,有名字
                2,全双工(通信双方可以同时收发数据)
               3,可以没有亲属关系(因为有名字,就像文件一样,其他程序可以通过文件名获取文件描述符的方式进行操作此管道)
               4,管道默认会阻塞 (例如在没数据的时候去读,就会等待、直到有数据;在管带数据满的时候想写数据,就会进行等待、直到有位置写入)
                5,不能用lseek定位 (不能指定的读取 某个位置的数据)
                6,操作有原子性 (一个动作要么执行成功、要么执行失败、不会执行到一半)

二、无名管道

       

pipe()函数
功能 创建无名管道
头文件 #include <unistd.h>
原型 int pipe(int pipefd[2]);
参数 pipefd:管道的读写描述符,其中pipefd[0]是读描述符,pipefd[1]是写描述符。
返回值

成功:返回0

失败:返回-1,并且设置错误号error

            EFAULT pipefd无效。
            EMFILE进程正在使用太多文件描述符。
            ENFILE已打开文件总数的到达系统限制。

备注  

测试代码1:

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

int main(void)
{
	char buffer[100];
	int retval;


	int pipe_fd[2];

	pipe(pipe_fd);

	pid_t pid;

	pid = fork();
	if(pid == 0)
	{
		while(1)
		{
			memset(buffer, 0, sizeof(buffer));//清空上次数据,防止残留
			retval = read(pipe_fd[0], buffer, sizeof(buffer));
			if(retval == -1)
			{
				perror("read pipe failed\n");
				exit(EXIT_FAILURE);
			}
			printf("buffer=[%s]\n", buffer);
			
			if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 )//如果读取到的是exit,则退出
			{
				break;
			}
		}
		exit(EXIT_SUCCESS);
	}

	while(1)
	{
		fgets(buffer, sizeof(buffer), stdin);
		buffer[strlen(buffer)-1] = '\0';//fgets()会读取回车

		retval = write(pipe_fd[1], buffer, strlen(buffer));
		if(retval == -1)
		{
			perror("write error\n");
			break;
		}
		else if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 )
		{
			break;
		}
	}

	return 0;
}

运行结果:最后一个exit输出到命令提示符后面是因为:子进程退出慢于主进程,而默认主进程退出之后就会输出命令提示符

 

 测试代码2:

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

void signal_handle(int signum)
{
	printf("recv SIGPIPE\n");
}

int main(void)
{
	char buffer[100];
	int retval;
	int pipe_fd[2];

	pipe(pipe_fd);
	pid_t pid;

	signal(SIGPIPE, signal_handle);
	
	pid = fork();
	if(pid == 0)
	{
		printf("111\n");
		pause();
		printf("222\n");

		retval = read(pipe_fd[0], buffer, sizeof(buffer));
		if(retval == -1)
		{
			perror("read pipe failed\n");
			exit(EXIT_FAILURE);
		}

		printf("buffer=%s\n", buffer);

		exit(EXIT_SUCCESS);
	}

	fgets(buffer, sizeof(buffer), stdin);

	retval = write(pipe_fd[1], buffer, strlen(buffer));
	if(retval == -1)
	{
		perror("write error\n");
	}

	printf("ok\n");
	return 0;
}

 运行结果:

三、有名管道

   

mkfifo()函数
功能 创建有名管道(一种特殊的文件)
头文件 #include <sys/types.h>
 #include <sys/stat.h>
原型 int mkfifo(const char *pathname, mode_t mode);
参数

pathname:管道的名字

mode:创建方式(限定权限之类,类似open()函数)

返回值

成功:返回0

失败:返回-1,并设置error

           EEXIST      管道已存在

           EACCES      权限不足

备注 读取操作会取走管道数据,关闭管道会清空管道数据。

       

        测试代码1:进程间通过管道进行通信(数据传输)

       fifo.c文件

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

#define	PATH	"/home/liang/myfifo"

int main(void)
{
	int retval;

	if(access(PATH, F_OK))//access()判断文件是否存在,存在返回0
	{
		retval = mkfifo(PATH, 0665);//创建有名管道、并设置权限
		if(retval == -1)
		{
			perror("creat fifo error\n");
			return -1;
		}
		printf("create fifo success\n");
	}

	int fifo_fd;
	fifo_fd = open(PATH, O_RDWR);//打开有名管道
	if(fifo_fd == -1)
	{
		perror("open fifo error\n");
		return -1;
	}

	char buffer[100];

	while(1)
	{
		fgets(buffer, sizeof(buffer), stdin);
		buffer[strlen(buffer)-1] = '\0';//fgets()会读取回车
		
		retval = write(fifo_fd, buffer, strlen(buffer));
		if(retval == -1)
		{
			perror("write error\n");
			break;
		}
		else if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 ) 
		{
			break;
		}
	}


	close(fifo_fd);

	return 0;
}

      fiforead.c文件

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

#define	PATH	"/home/liang/myfifo"

int main(void)
{
	int retval;

	if(access(PATH, F_OK))
	{
		retval = mkfifo(PATH, 0666);
		if(retval == -1)
		{
			perror("creat fifo error\n");
			return -1;
		}
                printf("create fifo success\n");
	}


	int fifo_fd;

	fifo_fd = open(PATH, O_RDWR);
	if(fifo_fd == -1)
	{
		perror("open fifo error\n");
		return -1;
	}

	char buffer[100];

	while(1)
	{
		memset(buffer, 0, sizeof(buffer));
		retval = read(fifo_fd, buffer, sizeof(buffer));
		if(retval == -1)
		{
			perror("read error\n");
			break;
		}
		printf("read fifo=[%s]\n", buffer);
		if(strlen(buffer) == 4 && strncmp(buffer, "exit", 4) == 0 ) 
		{
			break;
		}
	}


	close(fifo_fd);

	return 0;
}

        运行结果:

       

测试代码2:管道关闭之后,管道内容会清空。

fifo.c

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

#define	PATH	"/home/liang/myfifo"

int main(void)
{
	int retval;

	if(access(PATH, F_OK))//access()判断文件是否存在,存在返回0
	{
		retval = mkfifo(PATH, 0665);//创建有名管道、并设置权限
		if(retval == -1)
		{
			perror("creat fifo error\n");
			return -1;
		}
		printf("create fifo success\n");
	}

	int fifo_fd;
	fifo_fd = open(PATH, O_RDWR);//打开有名管道
	if(fifo_fd == -1)
	{
		perror("open fifo error\n");
		return -1;
	}

	char buffer[100];
	memset(buffer, 0, sizeof(buffer));

	printf("write data to fifo:");
	fgets(buffer, sizeof(buffer), stdin);
	buffer[strlen(buffer)-1] = '\0';//fgets()会读取回车
	
	retval = write(fifo_fd, buffer, strlen(buffer));
	if(retval == -1)
	{
		perror("write error\n");
	}
	printf("write data ok!\n");
	close(fifo_fd);

	return 0;
}

fiforead.c

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

#define	PATH	"/home/liang/myfifo"

int main(void)
{
	int retval;

	if(access(PATH, F_OK))
	{
		retval = mkfifo(PATH, 0666);
		if(retval == -1)
		{
			perror("creat fifo error\n");
			return -1;
		}
		printf("create fifo success\n");
	}
	
	int fifo_fd;

	fifo_fd = open(PATH, O_RDWR);
	if(fifo_fd == -1)
	{
		perror("open fifo error\n");
		return -1;
	}

	char buffer[100];
	memset(buffer, 0, sizeof(buffer));

	printf("wait for data!\n");
	retval = read(fifo_fd, buffer, sizeof(buffer));
	if(retval == -1)
	{
		perror("read error\n");
	}
	printf("read fifo=[%s]\n", buffer);

	printf("read data ok\n");
	close(fifo_fd);

	return 0;
}

运行结果:

猜你喜欢

转载自blog.csdn.net/nanfeibuyi/article/details/81907592
今日推荐