文章目录
- 前言
- 异步IO示例
- 带回调的异步IO
- 使用aio_read的echo服务
- 总结
前言
POXSIX提供了用于异步I/O的"aio_xxx"函数集。
名称 | 功能 |
---|---|
aio_read | 异步read |
aio_write | 异步write |
aio_fsync | 异步fsync |
aio_error | 获取错误状态 |
aio_return | 获取返回值 |
aio_cancel | 请求取消 |
aio_suspend | 请求等待 |
异步IO示例
#include <aio.h>#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>int main(int argc, char* argv[])
{if (argc < 2) return 1;struct aiocb cb;const struct aiocb* cblist[1];char buf[BUFSIZ];int fd, n;fd = open(argv[1], O_RDONLY);if (fd < 0) {perror("open");exit(EXIT_FAILURE);}memset(&cb, 0, sizeof(struct aiocb));cb.aio_fildes = fd;cb.aio_buf = buf;cb.aio_nbytes = BUFSIZ-1;n = aio_read(&cb);if (n < 0) {perror("aio_read");exit(EXIT_FAILURE);}cblist[0] = &cb;n = aio_suspend(cblist, 1, NULL);if (n != 0) {perror("aio_read");exit(EXIT_FAILURE);}n = aio_return(&cb);if (n < 0) {perror("aio_return");exit(EXIT_FAILURE);}buf[n] = '\0';printf("%s\n", buf);return 0;
}
将aio_read, aio_suspend, aio_return 放在循环中时不能正确读取内容超过缓冲区大小的内容
带回调的异步IO
在回调函数的调用上,有信号和线程两种方式,下面时使用线程进行回调的方式。
如果用SIGEV_THREAD设置回调函数并调用aio_read,从系统内部来看,实际上是用多个线程来实现异步IO。
#include <aio.h>
// #include <asm-generic/siginfo.h>#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>static void read_done(__sigval_t sigval)
{struct aiocb *cb;int n;cb = (struct aiocb*)(sigval.sival_ptr);if (aio_error(cb) == 0){n = aio_return(cb);if (n < 0){perror("aio_return");exit(EXIT_FAILURE);}printf("%d %d ---\n%.*s", n, cb->aio_nbytes, cb->aio_nbytes, cb->aio_buf);exit(EXIT_SUCCESS);}return;
}int main(int argc, char* argv[])
{if (argc < 2) return 1;struct aiocb cb;char buf[BUFSIZ] = {'\0'};int fd, n;fd = open(argv[1], O_RDONLY);if (fd < 0) {perror("open");exit(EXIT_FAILURE);}memset(&cb, 0, sizeof(struct aiocb));cb.aio_fildes = fd;cb.aio_buf = buf;cb.aio_nbytes = BUFSIZ-1;cb.aio_sigevent.sigev_notify = SIGEV_THREAD;cb.aio_sigevent.sigev_notify_function = &read_done;cb.aio_sigevent.sigev_value.sival_ptr = &cb;n = aio_read(&cb);if (n < 0) {perror("aio_read");exit(EXIT_FAILURE);}select(0, NULL, NULL, NULL, NULL);return 0;
}
使用aio_read的echo服务
#include <aio.h>
// #include <asm-generic/siginfo.h>#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>static void read_done(__sigval_t sigval)
{struct aiocb *cb;int n;cb = (struct aiocb*)(sigval.sival_ptr);if (aio_error(cb) == 0){n = aio_return(cb);if (n < 0){perror("aio_return");exit(EXIT_FAILURE);} else if (0 == n) {printf("client %d gone\n", cb->aio_fildes);aio_cancel(cb->aio_fildes, cb);close(cb->aio_fildes);free(cb);return;}printf("client %d (%d)\n", cb->aio_fildes, n);write(cb->aio_fildes, cb->aio_buf, n);aio_read(cb);}else{printf("aio_error\n");}return;
}
static void register_read(int fd)
{struct aiocb *cb;char* buf;printf("client register %d\n", fd);cb = malloc(sizeof(struct aiocb));buf = malloc(BUFSIZ);memset(cb, 0, sizeof(struct aiocb));cb->aio_fildes = fd;cb->aio_buf = buf;cb->aio_nbytes = BUFSIZ;cb->aio_sigevent.sigev_notify = SIGEV_THREAD;cb->aio_sigevent.sigev_notify_function = read_done;cb->aio_sigevent.sigev_value.__sival_ptr = cb;//if (aio_read(cb) != 0){perror("aio_read");return;}
}int main(int argc, char* argv[])
{if (argc < 2) return 1;struct sockaddr_in addr;int s = socket(PF_INET, SOCK_STREAM, 0);addr.sin_family = AF_INET;addr.sin_addr.s_addr = INADDR_ANY;addr.sin_port = htons(9999);if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) != 0) {perror("bind");exit(EXIT_FAILURE);}listen(s, 5);for (;;){int c = accept(s, NULL, 0);if (c < 0) continue;register_read(c);}return 0;
}