目录
概述:
管道 进程通信
管道 使用最简单
信号 开销最小
共享映射区 无血缘关系
本地套接字 最稳定 难度最强pipe 函数 未名管道
管道一般读写行为fifo 有名管道
用于非血缘关系进程通信共享内存
mmap 函数的参数使用注意事项
用于非血缘关系进程通信linux 文件类型
- 文件
d 目录
l 符号链接
s 套接字
b 块设备
c 字符设备
p 管道前三种占用磁盘存储
后四种 为 伪文件 实质是一个内核缓冲区
由两个文件描述符引用,一个表示读端,一个表示写端
规定数据从管道的写端流入管道,从读端流出。
管道原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现磁盘扇区 一个文件最小要占用一个扇区512b pipe 占用了8个 所以就是8X512b =4K 4个字节
管道数据不能重复读取,读队列就相当于数据出队,不能重复读,且不能入队的一边读,比如不能自己往管道写入数据,
然后再自己读出来,这样是不可以的。
管道半双工通信,数据只能在一个方向上通信。既可以只往左流动,也可以只往右流,但是不能同时突然往左突然往右,这是全双工。
只能在有公共祖先的进程间通信。
pipe API:
SYNOPSIS
#include <unistd.h>int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>int pipe2(int pipefd[2], int flags);
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.DESCRIPTION
pipefd[0] refers to the read end of the pipe.
pipefd[1] refers to the write end of the pipe. Data written to the write end of
the pipe is buffered by the kernel until it is read from the read end of the pipe.
pipefd数组 pipefd[0] 代表读端 pipefd[1]代表写端。
补充:
读管道
①管道中有数据 read返回读到的字节数。
② 管道中无数据 ,写端全部关闭,read返回0;仍然有写端打开:阻塞等待。
写管道
①读端全部关闭,进程异常终止(SIGPIPE信号)
②有读端打开, 管道未满:写数据,返回写入字节数; 管道已满,:阻塞(少见)。
父子进程通信 ls | wc -l
兄弟进程间通信
获取管道缓冲区大小
命令: ulimit -a
函数:fpathconf 参数2: __PC_PIPE_BUF
优点 实现简单
缺点:单向 只能有血缘的进程。
FIFO:
命名管道(Linux基础文件类型)
创建
命令: mkfifo
函数:mkfifo 参数 name , mode:八进制 。 返回值 成功 0 ,失败 -1,设置error。
没有血缘关系进程间通信: 使用同一FIFO,可多读端,多写端。
也必须在同一路径下才行。
共享存储映射:
mmap函数: 参数:
返回值:
借助共享内存访问磁盘文件。
借助指针访问磁盘文件。
父子进程、血缘关系进程、通信 。
匿名映射区 如何创建 使用。
mmap API
SYNOPSIS
#include <sys/mman.h>void *mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset);
DESCRIPTION
This is probably not the system call you are interested; instead, see mmap(2), which describes
the glibc wrapper function that invokes this system call.The mmap2() system call provides the same interface as mmap(2), except that the final argument
specifies the offset into the file in 4096-byte units (instead of bytes, as is done by
mmap(2)). This enables applications that use a 32-bit off_t to map large files (up to 2^44
bytes).RETURN VALUE
On success, mmap2() returns a pointer to the mapped area. On error -1 is returned and errno is
set appropriately.
参数:
addr: 建立映射区的首地址 linux内核自动指定,使用时直接传NULL
length: 欲创建映射区大小
prot: 映射区权限,PROT_READ PROT_WRITE PROT_READ|PROT_WRITE
flags: 标志位参数(常用语设定更新物理区域、设置共享内存、创建匿名映射区)
MAP_SHARED:会将映射区所做的操作反映到物理设备(磁盘)上。
MAP_PRIVATE:映射区所做的修改不会反映到物理设备上。
fd: 用来建立映射区的文件描述符
offset:映射文件的偏移(4K的整数倍)4096的整数倍
文件打开函数
lseek函数
ftruncate函数
其他注意事项:
- 映射区的权限小于等于打开文件的权限,而且定义映射区的时候,会隐含一次读文件的操作
- 映射区一单创建成功,文件描述符就没用了,及时早关闭也不会对mmap产生影响了。
- mem++ munmap不会成功
- 映射区的释放与文件关闭无关,只要映射区成功建立,文件可以立即关闭。
- 特别注意,当映射文件大小为0时,不能创建映射区。所以映射的文件必须要要有实际大小。mmap使用时常常会出现总线错误,通常是由于共享文件存储空间大小引起的。
- munmap 传入的地址一定是mmap的返回地址。
- 如果文件偏移量必须为4k整数倍
- mmap创建映射区出错的概率非常高,一定要检查返回值,确保创建成功再后续操作。
- 杜绝映射区首地址++ -- 操作。
mmap练习代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/mman.h>
#include<string.h>
#include<fcntl.h>
int main()
{
int len, ret;
char *p = NULL;
int fd = open("mytest.txt",O_CREAT|O_RDWR,0644);
if(fd < 0){
perror("open error:");
exit(1);
}
len = ftruncate(fd,4);
if (len == -1){
perror("ftruncate error:");
exit(1);
}
p = (char*)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//创建映射区
if (p == MAP_FAILED){
perror("mmap error:");
exit(1);
}
strcpy(p,"abc"); //写数据
ret = munmap(p,4);//释放映射区
if (ret == -1){
perror("munmap error:");
exit(1);
}
close(fd);
return 0;
}