Linux 进程间通信(一)

1.IPC

     进程间通信    interProcess Communication

2.管道(匿名)

1)管道的概念

  • 本质:内核缓冲区
    • 伪文件:不占用磁盘空间
  • 特点
    • 两部分:
      • 读端,写端,对应两个文件描述符
      • 数据写端流入,读端流出
    • 操作管道的进程被销毁之后,管道自动被释放
    • 管道默认是阻塞的 
      • 读写

2)管道的原理

  • 内部实现方式:队列
    • 环形队列
    • 特点:先进先出
  • 缓冲区大小:
    • 默认4K
    • 大小会根据实际情况做适当调整

3)管道的局限性

  • 队列:
    • 数据只能读取一次,不能重复读取
  • 半双工
  • 匿名管道:适用于有血缘关系的进程

4)创建匿名管道 pipe

表头文件

#include<unistd.h>

定义函数

int pipe(int filedes[2]);

函数说明

pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。

返回值

若成功则返回零,否则返回-1,错误原因存于errno中。

错误代码

EMFILE 进程已用完文件描述词最大量。
ENFILE 系统已无文件描述词可用。
EFAULT 参数filedes数组地址不合法。

5)父子进程使用管道通信

/* 父进程借管道将字符串“hello!\n”传给子进程并显示*/
#include <unistd.h>
int main(){
	int filedes[2];
	char buffer[80];
	pipe(filedes);
	if (fork()>0) {
		/* 父进程*/
		char s[] = "hello!\n";
		write(filedes[1], s, sizeof(s));
	}
	else {
		/*子进程*/
		read(filedes[0], buffer, 80);
		printf("%s", buffer);
	}
    return 0;
}

 hello!

6)管道读写行为

  • 读操作

    • 有数据

      • read(fd)-正常读,返回读出的字节数

    • 无数据

      • 写端全部关闭

        • read解除阻塞,返回0

        • 相当于读文件读到尾部

      • 没有全部关闭

        • read阻塞

  • 写操作

    •  读端全部关闭

      • 管道破裂,进程被终止

        • 内核给当前进程发信号SIGPIPE

    • 没有全部关闭

      • 缓冲区写满了

        • write阻塞

      • 缓冲区没有满

        • write继续写

  • 如何设置非阻塞

    • 默认读写两端都阻塞

    • 设置读端为非阻塞pipe(fd)

      • fcntl  变参函数

        • 复制文件描述符 - dup

        • 修改文件属性 - open时对应flag属性

      • 设置方法:

        • 获取原来的flags

          • int flags = fcntl(fd[0],F_GETFL);

        • 设置新的flags

          • flags |= O_NONBLOCK;

          • fcntl(fd[0],F_SETFL,flags);

7)查看管道缓冲区的大小

  • 命令
    • ulimit -a
  • 函数
    • fpathconf

3.FIFO

1)特点

  • 有名管道
  • 在磁盘上有这样一个文件 ls -l -》p
  • 伪文件,文件在磁盘大小为0
  • 在内核中有一个对应的缓冲区
  • 半双工的通信方式

2)使用场景

  • 没有血缘关系的进程间通信

3)创建方式

  • 命令:mkfifo 管道名
  • 函数:mkfifo

表头文件

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

定义函数

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

函数说明

mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开FIFO文件时,O_NONBLOCK旗标会有影响
1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。

返回值

若成功则返回0,否则返回-1,错误原因存于errno中。

错误代码

EACCESS 参数pathname所指定的目录路径无可执行的权限
EEXIST 参数pathname所指定的文件已存在。
ENAMETOOLONG 参数pathname的路径名称太长。
ENOENT 参数pathname包含的目录不存在
ENOSPC 文件系统的剩余空间不足
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
EROFS 参数pathname指定的文件存在于只读文件系统内。

4)fifo文件可以使用io函数进行操作

  • open/close
  • read/write
  • 不能执行lseek操作

5)进程间通信

a.fifo文件 --- myfifo

  • 两个不相干的进程A(a.c) B(b.c)
  • a.c  --》 read
    • int fd = open("myfifo",O_RDONLY);
    • read(fd,buf,sizeof(buf));
    • close(fd);
  • b.c  --》 write
    • int fd1 = open("myfifo",O_WRONLY);
    • write(fd1,"hello,world",11);
    • close(fd);
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <iostream>
using namespace std;

#define FIFO "./abc"
int main() {
		char buffer[80];
		int fd;
		unlink(FIFO);
		mkfifo(FIFO, 0666);
		if (fork()>0) {
			char s[] = "hello!\n";
			fd = open(FIFO, O_WRONLY);
			write(fd, s, sizeof(s));
			close(fd);
		}
		else {
			fd = open(FIFO, O_RDONLY);
			read(fd, buffer, 80);
			printf("%s", buffer);
			close(fd);
		}
	return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值