1. epoll与aio的区别
1.1 文件描述符的分类
网络 io : socketFd
文件 io : fd
1.2 Windows与Linux异步操作的区别
windows: 所有描述符号的异步操作都是 iocp
linux: 针对socketFd 使用epoll做专门的操作(io多路复用)
针对fd 使用aio做专门的操作(异步io)
2. aio的执行过程
**涉及到OS的状态切换:
让io过程异步进行从而提高线程读写效率
aio执行完毕后会 立即 返回
两种方式来操作需要操作的数据:1. 检查(被检查) 2. 通知(信号 信号量 回调函数)(主动通知)**
3. aio编程模型
- 准备缓冲区(读到的数据存储的指定位置 struct aiocb cb
- 异步操作 异步读 异步写 aio_read aio_write
- 检查是否(读写)操作完毕 aio_error 循环检查
**aio\_suspend** 阻塞式
- 得到数据 aio_return
4. aio异步读检查方式实现
//异步读实现(检查方式)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <aio.h>
#include <string.h>
#include <fcntl.h>
#define BUFF_SIZE 1024 //缓冲大小
int main(){
//1. 准备缓冲区
struct aiocb cb = {0};
int fd = open("test.txt",O_RDONLY);
if(-1 == fd) printf("文件打开失败:%m\n"),exit(-1);
printf("文件打开成功!\n");
//2. 异步读取文件数据
cb.aio_buf = malloc(BUFF_SIZE + 1); //开辟内存空间
memset(cb.aio_buf,0,BUFF_SIZE + 1); //清空内存
cb.aio_fildes = fd; //文件描述符
cb.aio_nbytes = BUFF_SIZE; //读取数据大小
cb.aio_offset = 0; //文件偏移量
int r = aio_read(&cb);
if(-1 == r) printf("异步读取失败:%m\n"),close(fd),exit(-2);
printf("异步读取成功!\n");
//3. 检查是否读取数据完毕
int n = 0;
while(aio_error(&cb)) n++;
//4. 得到数据
r = aio_return(&cb);
if(r > 0){
printf("拿到了数据:n:%d,r:%d bytes,data: %s\n",
n,r,cb.aio_buf);
}
//5. 释放内存 关闭文件
free(cb.aio_buf);
close(fd);
return 0;
}
5. aio异步读阻塞方式实现
//异步读实现(阻塞方式)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <aio.h>
#include <string.h>
#include <fcntl.h>
#define BUFF_SIZE 1024
#define AIO_LIST_NUM 2 //aio个数
int main(){
//1. 准备缓冲区
struct aiocb cb = {0};
//准备aio_suspend的第一个参数 结构体指针数组
struct aiocb* aiocb_list[AIO_LIST_NUM] = {0};
int fd = open("test.txt",O_RDONLY);
if(-1 == fd) printf("文件打开失败:%m\n"),exit(-1);
printf("文件打开成功!\n");
//2. 异步读取文件数据
cb.aio_buf = malloc(BUFF_SIZE + 1); //开辟内存空间
memset(cb.aio_buf,0,BUFF_SIZE + 1); //清空内存
cb.aio_fildes = fd; //文件描述符
cb.aio_nbytes = BUFF_SIZE; //读取数据大小
cb.aio_offset = 0; //文件偏移量
int r = aio_read(&cb);
if(-1 == r) printf("异步读取失败:%m\n"),close(fd),exit(-2);
printf("异步读取成功!\n");
//将结构体cb设置到aio_suspend监视数组中去
aiocb_list[0] = &cb;
//3. aio_suspend阻塞式等待
printf("阻塞!\n");
r = aio_suspend(aiocb_list,AIO_LIST_NUM,NULL);
if(-1 == r) printf("aio_suspend失败:%m\n"),close(fd),exit(-3);
printf("aio_suspend成功!\n");
printf("阻塞结束!\n");
//4. 得到数据
r = aio_return(&cb);
if(r > 0){
printf("拿到了数据:r:%d bytes,data: %s\n",
r,cb.aio_buf);
}
//5. 释放内存 关闭文件
free(cb.aio_buf);
close(fd);
return 0;
}
6. aio异步读写实现
//异步读写实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <aio.h>
#include <string.h>
#include <fcntl.h>
#define BUFF_SIZE 1024
#define AIO_LIST_NUM 2 //aio个数
int main(){
//1. 准备缓冲区
struct aiocb rcb = {0};
struct aiocb wcb = {0};
//准备lio_listio的第二个参数 结构体指针数组
struct aiocb* aiocb_list[AIO_LIST_NUM] = {NULL};
//2. 异步读取文件数据
int rfd = open("test.txt",O_RDONLY);
if(-1 == rfd) printf("文件打开失败:%m\n"),exit(-1);
printf("文件打开成功!\n");
rcb.aio_buf = malloc(BUFF_SIZE + 1); //开辟内存空间
memset(rcb.aio_buf,0,BUFF_SIZE + 1); //清空内存
rcb.aio_fildes = rfd; //文件描述符
rcb.aio_nbytes = BUFF_SIZE; //读取数据大小
rcb.aio_offset = 0; //文件偏移量
rcb.aio_lio_opcode = LIO_READ; //设置操作方式
//将结构体rcb设置到aio_suspend监视数组中去
aiocb_list[0] = &rcb;
//3. 异步写入文件数据
int wfd = open("test1.txt",O_WRONLY | O_APPEND);
if(-1 == wfd) printf("文件打开失败:%m\n"),exit(-3);
printf("文件打开成功!\n");
wcb.aio_buf = malloc(BUFF_SIZE + 1); //开辟内存空间
memset(wcb.aio_buf,0,BUFF_SIZE + 1); //清空内存
strcpy(wcb.aio_buf,"哈哈哈哈\n"); //准备要写入的数据
wcb.aio_fildes = wfd; //文件描述符
wcb.aio_nbytes = strlen("哈哈哈哈\n"); //写入数据大小
wcb.aio_lio_opcode = LIO_WRITE; //设置操作方式
//将结构体wcb设置到aio_suspend监视数组中去
aiocb_list[1] = &wcb;
//4. lio_listio 监控多个io
int r = lio_listio(LIO_WAIT,aiocb_list,AIO_LIST_NUM,NULL);
printf("lio_listio r: %d\n",r);
//5. 得到数据
r = aio_return(&rcb);
if(r > 0){
printf("拿到了数据:r:%d bytes,data: %s\n",
r,rcb.aio_buf);
}
r = aio_return(&wcb);
if(r > 0){
printf("写入数据成功:r %d\n",r);
}
//6. 释放内存 关闭文件
free(rcb.aio_buf);
free(wcb.aio_buf);
close(rfd);
close(wfd);
return 0;
}
7. aio注意项
使用 aio 的一些函数时需要加载 rt 库
**Windows中库的加载:
#include <mmsystem.h> #pragma comment(lib,"winmm.lib") //库的加载
Linux中库的加载在编译链接时做:
gcc -c aio.c
gcc aio.o //不加载库gcc -c aio.c gcc aio.o -l rt //加载库 gcc aio.c -lrt**