码迷,mamicode.com
首页 > 系统相关 > 详细

进程间通信

时间:2021-01-25 10:42:24      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:磁盘   world   ipc   types   errno   进程关闭   limit   alt   linux基础   

一、什么是进程间通信?
Linux环境下,进程地址空间是相互独立的,每个进程有各自独立的用户地址空间,进程之间的全局变量在另一个进程中都看不到,要交换数据必须通过内核。进程1把数据写入内核的一个缓冲区,另一个进程可以从内核缓冲区读走,内核提供的这种机制就是进程间通信IPC(InterProcess Communication)。
二、常用进程间通信方式
1.管道-pipe
①管道也称匿名管道,应用于有血缘关系的进程通信。
技术图片
管道特质:
(1)管道本质是一块内核缓冲区。
(2)由两个文件描述符引用,一个读端,一个写端。
(3)数据从写端流入,读端流出。
(4)当两个进程都终结的时候,管道也自动消失。
(5)管道的读端和写端都是默认阻塞的。

②管道的原理:
管道的实质是内核缓冲区,内部使用环形队列实现,默认缓冲区大小为4K,可以使用ulimit -a命令获取大小,实际操作过程中缓冲区会根据数据压力做适当调整。

③管道的局限性:
(1)不可以反复读取,数据一旦读走便不在管道中存在。
(2)数据只能单向流动,需要两个管道才能实现双向流动。
(3)只能在有血缘关系的进程间使用管道。因为没有血缘关系的进程无法获取管道描述符。

④创建管道:
使用pipe函数创建管道:函数原型:

        int pipe(int fd[2]);

        若函数调用成功,返回0,fd[0]存放管道的读端,fd[1]存放管道的写端。
        调用失败返回-1,并设置errno值。

⑤管道实例:
父子进程间通信:
(1)父进程创建管道
技术图片
(2)父进程fork出子进程
技术图片
(3)父进程关闭fd[0],子进程关闭fd[1]
技术图片

代码:

include <stdio.h>

include <stdlib.h>

include <string.h>

include <sys/types.h>

include <unistd.h>

include <sys/wait.h>

int main()
{
//创建管道
//int pipe(int pipefd[2]);
int fd[2];
int ret = pipe(fd);
if(ret<0)
{
perror("pipe error");
return -1;
}

//创建子进程
pid_t pid = fork();
if(pid<0) 
{
	perror("fork error");
	return -1;
}
else if(pid>0)
{
	//关闭读端
	close(fd[0]);
	sleep(5);
	write(fd[1], "hello world", strlen("hello world"));	

	wait(NULL);
}
else 
{
	//关闭写端
	close(fd[1]);
	
	char buf[64];
	memset(buf, 0x00, sizeof(buf));
	int n = read(fd[0], buf, sizeof(buf));
	printf("read over, n==[%d], buf==[%s]\n", n, buf);

}

return 0;

}

⑥管道的读写行为:
(1)读操作
有数据:read正常读,返回读出的字节数
无数据:写端全部关闭
read解除阻塞,返回0,相当于读文件读到了尾部
没有全部关闭
read阻塞
(2)写操作
读端全部关闭:管道破裂,进程终止,内核给当前进程发SIGPIPE信号
读端没全部关闭:
缓冲区写满了:write阻塞
缓冲区没有满:继续write

⑦设置管道为非阻塞:
默认情况下,管道的读写两端都是阻塞的,若要设置读或者写端为非阻塞,则可参
考下列三个步骤进行:
第1步: int flags = fcntl(fd[0], F_GETFL, 0);
第2步: flag |= O_NONBLOCK;
第3步: fcntl(fd[0], F_SETFL, flags);

若是读端设置为非阻塞:
写端没有关闭,管道中没有数据可读,则read返回-1;
写端没有关闭,管道中有数据可读,则read返回实际读到的字节数
写端已经关闭,管道中有数据可读,则read返回实际读到的字节数
写端已经关闭,管道中没有数据可读,则read返回0

`int main()
{
//创建管道
//int pipe(int pipefd[2]);
int fd[2];
int ret = pipe(fd);
if(ret<0)
{
perror("pipe error");
return -1;
}
printf("pipe size[%ld]\n", fpathconf(fd[0], _PC_PIPE_BUF));
printf("pipe size
[%ld]\n", fpathconf(fd[1], _PC_PIPE_BUF));
//关闭写端
close(fd[1]);

//设置管道的读端为非阻塞
int flag = fcntl(fd[0], F_GETFL);
flag |= O_NONBLOCK;
fcntl(fd[0], F_SETFL, flag);

char buf[64];
memset(buf, 0x00, sizeof(buf));
int n = read(fd[0], buf, sizeof(buf));
printf("read over, n==[%d], buf==[%s]\n", n, buf);

return 0;

}`

⑧查看管道缓冲区大小:
(1)命令:ulimit -a
(2)函数:
long fpathconf(int fd, int name);
printf("pipe size[%ld]\n", fpathconf(fd[0], _PC_PIPE_BUF));
printf("pipe size
[%ld]\n", fpathconf(fd[1], _PC_PIPE_BUF));

2.FIFO命名管道
①管道只能用于有血缘关系的进程间通信,但是FIFO可以用以不相关的进程间交换数据
FIFO是Linux基础文件类型的一种(文件类型:p)但FIFO文件在磁盘上没有数据块,文件大小为0,仅仅用来标识内核中的一条通道。进程可以打开这个文件进行read/write,实际上也是在读取内核缓冲区,进而实现进程间通信

  ②创建FIFO命名管道
  (1)方式1:使用命令:mkfifo
  格式:mkfifo 管道名
  (2)方式2:使用函数:int mkfifo(const char *pathname, mode_t mode);

(未完待续)

进程间通信

标签:磁盘   world   ipc   types   errno   进程关闭   limit   alt   linux基础   

原文地址:https://www.cnblogs.com/luyimin/p/14313185.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!