Linux 之 IPC进程间通信(二、管道)

  1. 什么是管道
    1. 管道是Unix中最古老的进程间通信的形式;
    2. 管道是半双工的,数据只能向一个方向流动;
    3. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)进行通信;????
    4. 本质上是文件io操作;
    5. 最大的数据量为65556(64kb);
    6. 在shell中使用管道
      1. 命令格式如:cmd1 | cmd2;这种信息过滤也是通过管道实现
  2. 优缺点
    1. 能进行块数据的传输;
    2. 内容有上限;
    3. 要双端同时打开才能使用;

匿名管道pipe 

        关键函数

//准备文件描述符:fd[0]读、fd[1]写
int fdarr[2] = { 0 };

//创建管道:利用文件描述符数组,第一个读、第二个写
pipe(fdarr) != 0	//打开一个管道

//管道只能是单向的,读端关闭fd[1]、写端关闭fd[0]
close(fdarr[0])

// 读写操作
//写端
write(fdarr[1], buf, sizeof(buf));
//读端
read(fdarr[0], buf, sizeof(buf));

        用pipe无名管道实现父子进程间通信

#include<iostream>
#include <unistd.h>
using namespace std;
#include<string.h>

//匿名管道的训练
int main()
{
	int fdarr[2] = { 0 };//负责父-》子 fd[0]读、fd[1]写
	int fdarr2[2] = { 0 };//负责子-》父
	char buf[50] = { 0 };
	char resbuf[50] = { 0 };

	pid_t pid = 0;
	if (pipe(fdarr) != 0 || pipe(fdarr2) != 0)
	{
		perror("pipe error");
	}
	else {
		pid = fork();
		if (pid > 0)
		{//父亲
			//管道的读端关闭,执行写
			close(fdarr[0]);
			close(fdarr2[1]);
			while (1)
			{
				cout << "父进程发送:" << endl;
				fgets(buf, sizeof(buf),stdin);
				int wres = write(fdarr[1], buf, sizeof(buf));
				cout << "pid = " << getpid() << " 发送:" << buf << " res = " <<wres <<endl;
				bzero(buf, sizeof(buf));
				
				int res = read(fdarr2[0], buf, sizeof(buf));
				cout << "pid = " << getpid() << " 接收:" << buf<< " res = " << res <<endl;
				bzero(buf, sizeof(buf));
			}
		}
		else if (pid == 0)
		{
			close(fdarr[1]);
			close(fdarr2[0]);
			while (1)
			{
				int res = read(fdarr[0], resbuf, sizeof(resbuf));
				cout << "pid = " << getpid() << " 接收:" << buf << " res = " << res << endl;
				bzero(resbuf, sizeof(resbuf));

				cout << "子进程发送:" << endl;
				fgets(buf, sizeof(buf), stdin);
				int wres = write(fdarr2[1], buf, sizeof(buf));
				cout << "pid = " << getpid() << " 发送:" << buf << " res = " << wres << endl;
				bzero(buf, sizeof(buf));
			}
		}
	}
}
  1. Fork前创建管道,获得读端和写端的文件描述符、fork后关闭不需要的管道;
  2. 匿名管道不能修改通信方向(close(fdarr[0]));

命名管道fifo

//检测是否存在
access(pipepath.c_str(), F_OK)

//创建管道
mkfifo(pipepath.c_str(), 0007)	

//写端
open(pipepath.c_str(), O_WRONLY)	
write(Writefd, wbuf, sizeof(wbuf))

//读端
open(pipepath.c_str(), O_RDONLY)	
read(Readfd, rbuf, sizeof(rbuf))

命名管道-伪聊天

#include<iostream>
using namespace std;
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>

int main()
{
	string pipepath = "/home/wangcf/data/A2B.pipe";
	int wfd = 0;
	int Writefd = 0;
	char wbuf[50] = { 0 };

	string pipepath2 = "/home/wangcf/data/B2A.pipe";
	int rfd = 0;
	int Readfd = 0;
	char rbuf[50] = { 0 };

	umask(0);	

	if (access(pipepath.c_str(), F_OK) == 0)
	{
		cout << "pipe existence存在" << endl;
	}
	else {
		if(mkfifo(pipepath.c_str(), 0007) == -1)
			{
			perror("mkfifo error");
		}
	}

	if (access(pipepath2.c_str(), F_OK) == 0)
	{
		cout << "pipe2 existence存在" << endl;
	}
	else {
		if (mkfifo(pipepath2.c_str(), 0007) == -1)
		{
			perror("mkfifo error");
		}
	}

	Writefd = open(pipepath.c_str(), O_WRONLY);
	if (Writefd == -1)
	{
		perror("open error");
	}
	else {
		cout<<  "Writefd = " <<Writefd << endl;
	}

	Readfd = open(pipepath2.c_str(), O_RDONLY);
	if (Readfd == -1)
	{
		perror("open error");
	}
	else {
		cout << "Readfd = " << Writefd << endl;
	}

	wfd = fork();
	if (wfd == 0)
	{
		//写端
		while (1)
		{
			cin >> wbuf;
			int wres = write(Writefd, wbuf, sizeof(wbuf));
			cout << "A		:" << wbuf << endl;
			bzero(wbuf, sizeof(wbuf));
		}
	}
	else if (wfd > 0)
	{
		while (1) {
			int rres = read(Readfd, rbuf, sizeof(rbuf));
			cout << "B		:" << rbuf << endl;
			bzero(rbuf, sizeof(rbuf));
		}
	}
	return 0;
}

  1. Open函数
    1. 是阻塞式函数,一定要两段同时开启;
    2. 程序不能以O_RDWR模式打开FIFO文件进行读写;
  2. Read()为阻塞函数;
  3. 命名管道可以修改通信方向:
    1. (先关闭再重新打开FIFO的办法明确地改变数据流的方向);
  4. Fifo文件
    • 不会保留数据,永远大小为0;
    • 把管道删掉还能用,但是不合规。

用管道实现伪聊天!!!!!

未实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值