标签:磁盘 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]
代码:
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